Merge "servicedispatcher: exit when adb debugging is turned off."
diff --git a/cmds/cmd/fuzzer/Android.bp b/cmds/cmd/fuzzer/Android.bp
index 0c78c5a..8262bc2 100644
--- a/cmds/cmd/fuzzer/Android.bp
+++ b/cmds/cmd/fuzzer/Android.bp
@@ -14,6 +14,15 @@
* limitations under the License.
*/
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_cmds_cmd_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_cmds_cmd_license"],
+}
+
cc_fuzz {
name: "cmd_fuzzer",
srcs: [
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 87a10d3..2127f57 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -104,6 +104,7 @@
"BpBinder.cpp",
"BufferedTextOutput.cpp",
"Debug.cpp",
+ "FdTrigger.cpp",
"IInterface.cpp",
"IMemory.cpp",
"IPCThreadState.cpp",
@@ -123,6 +124,7 @@
"RpcSession.cpp",
"RpcServer.cpp",
"RpcState.cpp",
+ "RpcTransportRaw.cpp",
"Static.cpp",
"Stability.cpp",
"Status.cpp",
@@ -147,9 +149,6 @@
enabled: false,
},
host: {
- static_libs: [
- "libbase",
- ],
srcs: [
"ServiceManagerHost.cpp",
"UtilsHost.cpp",
@@ -190,6 +189,10 @@
"libutils",
],
+ static_libs: [
+ "libbase",
+ ],
+
header_libs: [
"libbinder_headers",
"libandroid_runtime_vm_headers",
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 628381c..d3eef4e 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -555,7 +555,9 @@
return status;
}
rpcServer->setRootObjectWeak(weakThis);
- rpcServer->setupExternalServer(std::move(socketFd));
+ if (auto status = rpcServer->setupExternalServer(std::move(socketFd)); status != OK) {
+ return status;
+ }
rpcServer->setMaxThreads(binderThreadPoolMaxCount);
rpcServer->start();
e->mRpcServerLinks.emplace(link);
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index 8676955..e4ac4b4 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -26,22 +26,6 @@
namespace android {
-std::string hexString(const void* bytes, size_t len) {
- if (bytes == nullptr) return "<null>";
-
- const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
- const char chars[] = "0123456789abcdef";
- std::string result;
- result.resize(len * 2);
-
- for (size_t i = 0; i < len; i++) {
- result[2 * i] = chars[bytes8[i] >> 4];
- result[2 * i + 1] = chars[bytes8[i] & 0xf];
- }
-
- return result;
-}
-
// ---------------------------------------------------------------------
static const char indentStr[] =
diff --git a/libs/binder/Debug.h b/libs/binder/Debug.h
index 7ca087e..262dfba 100644
--- a/libs/binder/Debug.h
+++ b/libs/binder/Debug.h
@@ -23,8 +23,6 @@
namespace android {
// ---------------------------------------------------------------------------
-std::string hexString(const void* data, size_t size);
-
const char* stringForIndent(int32_t indentLevel);
typedef void (*debugPrintFunc)(void* cookie, const char* txt);
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
new file mode 100644
index 0000000..e38ac63
--- /dev/null
+++ b/libs/binder/FdTrigger.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "FdTrigger"
+#include <log/log.h>
+
+#include <poll.h>
+
+#include <android-base/macros.h>
+
+#include "FdTrigger.h"
+namespace android {
+
+std::unique_ptr<FdTrigger> FdTrigger::make() {
+ auto ret = std::make_unique<FdTrigger>();
+ if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) {
+ ALOGE("Could not create pipe %s", strerror(errno));
+ return nullptr;
+ }
+ return ret;
+}
+
+void FdTrigger::trigger() {
+ mWrite.reset();
+}
+
+bool FdTrigger::isTriggered() {
+ return mWrite == -1;
+}
+
+status_t FdTrigger::triggerablePoll(base::borrowed_fd fd, int16_t event) {
+ while (true) {
+ pollfd pfd[]{{.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
+ {.fd = mRead.get(), .events = POLLHUP, .revents = 0}};
+ int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
+ if (ret < 0) {
+ return -errno;
+ }
+ if (ret == 0) {
+ continue;
+ }
+ if (pfd[1].revents & POLLHUP) {
+ return -ECANCELED;
+ }
+ return pfd[0].revents & event ? OK : DEAD_OBJECT;
+ }
+}
+
+} // namespace android
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
new file mode 100644
index 0000000..984e685
--- /dev/null
+++ b/libs/binder/FdTrigger.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#include <memory>
+
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+/** This is not a pipe. */
+class FdTrigger {
+public:
+ /** Returns nullptr for error case */
+ static std::unique_ptr<FdTrigger> make();
+
+ /**
+ * Close the write end of the pipe so that the read end receives POLLHUP.
+ * Not threadsafe.
+ */
+ void trigger();
+
+ /**
+ * Whether this has been triggered.
+ */
+ bool isTriggered();
+
+ /**
+ * Poll for a read event.
+ *
+ * event - for pollfd
+ *
+ * Return:
+ * true - time to read!
+ * false - trigger happened
+ */
+ status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
+
+private:
+ base::unique_fd mWrite;
+ base::unique_fd mRead;
+};
+} // namespace android
diff --git a/libs/binder/RpcAddress.cpp b/libs/binder/RpcAddress.cpp
index 98dee9a..ffc94b9 100644
--- a/libs/binder/RpcAddress.cpp
+++ b/libs/binder/RpcAddress.cpp
@@ -16,6 +16,7 @@
#include <binder/RpcAddress.h>
+#include <android-base/hex.h>
#include <binder/Parcel.h>
#include "Debug.h"
@@ -94,7 +95,7 @@
}
std::string RpcAddress::toString() const {
- return hexString(mRawAddr.get(), sizeof(RpcWireAddress));
+ return base::HexString(mRawAddr.get(), sizeof(RpcWireAddress));
}
status_t RpcAddress::writeToParcel(Parcel* parcel) const {
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 62ea187..a20445b 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -26,8 +26,10 @@
#include <android-base/scopeguard.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
+#include <binder/RpcTransportRaw.h>
#include <log/log.h>
+#include "FdTrigger.h"
#include "RpcSocketAddress.h"
#include "RpcState.h"
#include "RpcWireFormat.h"
@@ -37,39 +39,42 @@
using base::ScopeGuard;
using base::unique_fd;
-RpcServer::RpcServer() {}
+RpcServer::RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
+ : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {}
RpcServer::~RpcServer() {
(void)shutdown();
}
-sp<RpcServer> RpcServer::make() {
- return sp<RpcServer>::make();
+sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+ // Default is without TLS.
+ if (rpcTransportCtxFactory == nullptr)
+ rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
+ return sp<RpcServer>::make(std::move(rpcTransportCtxFactory));
}
void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
mAgreedExperimental = true;
}
-bool RpcServer::setupUnixDomainServer(const char* path) {
+status_t RpcServer::setupUnixDomainServer(const char* path) {
return setupSocketServer(UnixSocketAddress(path));
}
-bool RpcServer::setupVsockServer(unsigned int port) {
+status_t 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));
}
-bool RpcServer::setupInetServer(unsigned int port, unsigned int* assignedPort) {
- const char* kAddr = "127.0.0.1";
-
+status_t RpcServer::setupInetServer(const char* address, unsigned int port,
+ unsigned int* assignedPort) {
if (assignedPort != nullptr) *assignedPort = 0;
- auto aiStart = InetSocketAddress::getAddrInfo(kAddr, port);
- if (aiStart == nullptr) return false;
+ auto aiStart = InetSocketAddress::getAddrInfo(address, port);
+ if (aiStart == nullptr) return UNKNOWN_ERROR;
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
- InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
- if (!setupSocketServer(socketAddress)) {
+ InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, address, port);
+ if (status_t status = setupSocketServer(socketAddress); status != OK) {
continue;
}
@@ -80,7 +85,7 @@
int savedErrno = errno;
ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
strerror(savedErrno));
- return false;
+ return -savedErrno;
}
LOG_ALWAYS_FATAL_IF(len != sizeof(addr), "Wrong socket type: len %zu vs len %zu",
static_cast<size_t>(len), sizeof(addr));
@@ -93,11 +98,11 @@
*assignedPort = realPort;
}
- return true;
+ return OK;
}
- ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
+ ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", address,
port);
- return false;
+ return UNKNOWN_ERROR;
}
void RpcServer::setMaxThreads(size_t threads) {
@@ -152,14 +157,18 @@
LOG_ALWAYS_FATAL_IF(!mServer.ok(), "RpcServer must be setup to join.");
LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined");
mJoinThreadRunning = true;
- mShutdownTrigger = RpcSession::FdTrigger::make();
+ mShutdownTrigger = FdTrigger::make();
LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr, "Cannot create join signaler");
+
+ mCtx = mRpcTransportCtxFactory->newServerCtx();
+ LOG_ALWAYS_FATAL_IF(mCtx == nullptr, "Unable to create RpcTransportCtx with %s sockets",
+ mRpcTransportCtxFactory->toCString());
}
status_t status;
while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) {
unique_fd clientFd(TEMP_FAILURE_RETRY(
- accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC)));
+ accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC | SOCK_NONBLOCK)));
if (clientFd < 0) {
ALOGE("Could not accept4 socket: %s", strerror(errno));
@@ -220,6 +229,7 @@
LOG_RPC_DETAIL("Finished waiting on shutdown.");
mShutdownTrigger = nullptr;
+ mCtx = nullptr;
return true;
}
@@ -245,14 +255,29 @@
// mShutdownTrigger can only be cleared once connection threads have joined.
// It must be set before this thread is started
LOG_ALWAYS_FATAL_IF(server->mShutdownTrigger == nullptr);
+ LOG_ALWAYS_FATAL_IF(server->mCtx == nullptr);
+
+ status_t status = OK;
+
+ int clientFdForLog = clientFd.get();
+ auto client = server->mCtx->newTransport(std::move(clientFd), server->mShutdownTrigger.get());
+ if (client == nullptr) {
+ ALOGE("Dropping accept4()-ed socket because sslAccept fails");
+ status = DEAD_OBJECT;
+ // still need to cleanup before we can return
+ } else {
+ LOG_RPC_DETAIL("Created RpcTransport %p for client fd %d", client.get(), clientFdForLog);
+ }
RpcConnectionHeader header;
- status_t status = server->mShutdownTrigger->interruptableReadFully(clientFd.get(), &header,
- sizeof(header));
- if (status != OK) {
- ALOGE("Failed to read ID for client connecting to RPC server: %s",
- statusToString(status).c_str());
- // still need to cleanup before we can return
+ if (status == OK) {
+ status = client->interruptableReadFully(server->mShutdownTrigger.get(), &header,
+ sizeof(header));
+ if (status != OK) {
+ ALOGE("Failed to read ID for client connecting to RPC server: %s",
+ statusToString(status).c_str());
+ // still need to cleanup before we can return
+ }
}
bool incoming = false;
@@ -272,8 +297,8 @@
.version = protocolVersion,
};
- status = server->mShutdownTrigger->interruptableWriteFully(clientFd.get(), &response,
- sizeof(response));
+ status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &response,
+ sizeof(response));
if (status != OK) {
ALOGE("Failed to send new session response: %s", statusToString(status).c_str());
// still need to cleanup before we can return
@@ -342,7 +367,7 @@
}
if (incoming) {
- LOG_ALWAYS_FATAL_IF(!session->addOutgoingConnection(std::move(clientFd), true),
+ LOG_ALWAYS_FATAL_IF(OK != session->addOutgoingConnection(std::move(client), true),
"server state must already be initialized");
return;
}
@@ -351,7 +376,7 @@
session->preJoinThreadOwnership(std::move(thisThread));
}
- auto setupResult = session->preJoinSetup(std::move(clientFd));
+ auto setupResult = session->preJoinSetup(std::move(client));
// avoid strong cycle
server = nullptr;
@@ -359,21 +384,22 @@
RpcSession::join(std::move(session), std::move(setupResult));
}
-bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
+status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
LOG_ALWAYS_FATAL_IF(hasServer(), "Each RpcServer can only have one server.");
- unique_fd serverFd(
- TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ unique_fd serverFd(TEMP_FAILURE_RETRY(
+ socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
if (serverFd == -1) {
- ALOGE("Could not create socket: %s", strerror(errno));
- return false;
+ int savedErrno = errno;
+ ALOGE("Could not create socket: %s", strerror(savedErrno));
+ return -savedErrno;
}
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;
+ return -savedErrno;
}
// Right now, we create all threads at once, making accept4 slow. To avoid hanging the client,
@@ -383,16 +409,16 @@
if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 50 /*backlog*/))) {
int savedErrno = errno;
ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
- return false;
+ return -savedErrno;
}
LOG_RPC_DETAIL("Successfully setup socket server %s", addr.toString().c_str());
- if (!setupExternalServer(std::move(serverFd))) {
+ if (status_t status = setupExternalServer(std::move(serverFd)); status != OK) {
ALOGE("Another thread has set up server while calling setupSocketServer. Race?");
- return false;
+ return status;
}
- return true;
+ return OK;
}
void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) {
@@ -425,15 +451,15 @@
return std::move(mServer);
}
-bool RpcServer::setupExternalServer(base::unique_fd serverFd) {
+status_t RpcServer::setupExternalServer(base::unique_fd serverFd) {
LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
std::lock_guard<std::mutex> _l(mLock);
if (mServer.ok()) {
ALOGE("Each RpcServer can only have one server.");
- return false;
+ return INVALID_OPERATION;
}
mServer = std::move(serverFd);
- return true;
+ return OK;
}
} // namespace android
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 254b99c..4c47005 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -30,13 +30,16 @@
#include <android_runtime/vm.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
+#include <binder/RpcTransportRaw.h>
#include <binder/Stability.h>
#include <jni.h>
#include <utils/String8.h>
+#include "FdTrigger.h"
#include "RpcSocketAddress.h"
#include "RpcState.h"
#include "RpcWireFormat.h"
+#include "Utils.h"
#ifdef __GLIBC__
extern "C" pid_t gettid();
@@ -46,7 +49,8 @@
using base::unique_fd;
-RpcSession::RpcSession() {
+RpcSession::RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
+ : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {
LOG_RPC_DETAIL("RpcSession created %p", this);
mState = std::make_unique<RpcState>();
@@ -59,8 +63,11 @@
"Should not be able to destroy a session with servers in use.");
}
-sp<RpcSession> RpcSession::make() {
- return sp<RpcSession>::make();
+sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+ // Default is without TLS.
+ if (rpcTransportCtxFactory == nullptr)
+ rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
+ return sp<RpcSession>::make(std::move(rpcTransportCtxFactory));
}
void RpcSession::setMaxThreads(size_t threads) {
@@ -102,34 +109,63 @@
return mProtocolVersion;
}
-bool RpcSession::setupUnixDomainClient(const char* path) {
+status_t RpcSession::setupUnixDomainClient(const char* path) {
return setupSocketClient(UnixSocketAddress(path));
}
-bool RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
+status_t RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
return setupSocketClient(VsockSocketAddress(cid, port));
}
-bool RpcSession::setupInetClient(const char* addr, unsigned int port) {
+status_t RpcSession::setupInetClient(const char* addr, unsigned int port) {
auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
- if (aiStart == nullptr) return false;
+ if (aiStart == nullptr) return UNKNOWN_ERROR;
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port);
- if (setupSocketClient(socketAddress)) return true;
+ if (status_t status = setupSocketClient(socketAddress); status == OK) return OK;
}
ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port);
- return false;
+ return NAME_NOT_FOUND;
}
-bool RpcSession::addNullDebuggingClient() {
+status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
+ return setupClient([&](const RpcAddress& sessionId, bool incoming) -> status_t {
+ // std::move'd from fd becomes -1 (!ok())
+ if (!fd.ok()) {
+ fd = request();
+ if (!fd.ok()) return BAD_VALUE;
+ }
+ if (auto res = setNonBlocking(fd); !res.ok()) {
+ ALOGE("setupPreconnectedClient: %s", res.error().message().c_str());
+ return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code();
+ }
+ return initAndAddConnection(std::move(fd), sessionId, incoming);
+ });
+}
+
+status_t RpcSession::addNullDebuggingClient() {
+ // Note: only works on raw sockets.
+ if (auto status = initShutdownTrigger(); status != OK) return status;
+
unique_fd serverFd(TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC)));
if (serverFd == -1) {
- ALOGE("Could not connect to /dev/null: %s", strerror(errno));
- return false;
+ int savedErrno = errno;
+ ALOGE("Could not connect to /dev/null: %s", strerror(savedErrno));
+ return -savedErrno;
}
- return addOutgoingConnection(std::move(serverFd), false);
+ auto ctx = mRpcTransportCtxFactory->newClientCtx();
+ if (ctx == nullptr) {
+ ALOGE("Unable to create RpcTransportCtx for null debugging client");
+ return NO_MEMORY;
+ }
+ auto server = ctx->newTransport(std::move(serverFd), mShutdownTrigger.get());
+ if (server == nullptr) {
+ ALOGE("Unable to set up RpcTransport");
+ return UNKNOWN_ERROR;
+ }
+ return addOutgoingConnection(std::move(server), false);
}
sp<IBinder> RpcSession::getRootObject() {
@@ -188,83 +224,6 @@
return state()->sendDecStrong(connection.get(), sp<RpcSession>::fromExisting(this), address);
}
-std::unique_ptr<RpcSession::FdTrigger> RpcSession::FdTrigger::make() {
- auto ret = std::make_unique<RpcSession::FdTrigger>();
- if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) {
- ALOGE("Could not create pipe %s", strerror(errno));
- return nullptr;
- }
- return ret;
-}
-
-void RpcSession::FdTrigger::trigger() {
- mWrite.reset();
-}
-
-bool RpcSession::FdTrigger::isTriggered() {
- return mWrite == -1;
-}
-
-status_t RpcSession::FdTrigger::triggerablePoll(base::borrowed_fd fd, int16_t event) {
- while (true) {
- pollfd pfd[]{{.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
- {.fd = mRead.get(), .events = POLLHUP, .revents = 0}};
- int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
- if (ret < 0) {
- return -errno;
- }
- if (ret == 0) {
- continue;
- }
- if (pfd[1].revents & POLLHUP) {
- return -ECANCELED;
- }
- return pfd[0].revents & event ? OK : DEAD_OBJECT;
- }
-}
-
-status_t RpcSession::FdTrigger::interruptableWriteFully(base::borrowed_fd fd, const void* data,
- size_t size) {
- const uint8_t* buffer = reinterpret_cast<const uint8_t*>(data);
- const uint8_t* end = buffer + size;
-
- MAYBE_WAIT_IN_FLAKE_MODE;
-
- status_t status;
- while ((status = triggerablePoll(fd, POLLOUT)) == OK) {
- ssize_t writeSize = TEMP_FAILURE_RETRY(send(fd.get(), buffer, end - buffer, MSG_NOSIGNAL));
- if (writeSize == 0) return DEAD_OBJECT;
-
- if (writeSize < 0) {
- return -errno;
- }
- buffer += writeSize;
- if (buffer == end) return OK;
- }
- return status;
-}
-
-status_t RpcSession::FdTrigger::interruptableReadFully(base::borrowed_fd fd, void* data,
- size_t size) {
- uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
- uint8_t* end = buffer + size;
-
- MAYBE_WAIT_IN_FLAKE_MODE;
-
- status_t status;
- while ((status = triggerablePoll(fd, POLLIN)) == OK) {
- ssize_t readSize = TEMP_FAILURE_RETRY(recv(fd.get(), buffer, end - buffer, MSG_NOSIGNAL));
- if (readSize == 0) return DEAD_OBJECT; // EOF
-
- if (readSize < 0) {
- return -errno;
- }
- buffer += readSize;
- if (buffer == end) return OK;
- }
- return status;
-}
-
status_t RpcSession::readId() {
{
std::lock_guard<std::mutex> _l(mMutex);
@@ -312,10 +271,11 @@
}
}
-RpcSession::PreJoinSetupResult RpcSession::preJoinSetup(base::unique_fd fd) {
+RpcSession::PreJoinSetupResult RpcSession::preJoinSetup(
+ std::unique_ptr<RpcTransport> rpcTransport) {
// 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<RpcConnection> connection = assignIncomingConnectionToThisThread(std::move(fd));
+ sp<RpcConnection> connection = assignIncomingConnectionToThisThread(std::move(rpcTransport));
status_t status;
@@ -439,48 +399,48 @@
return server;
}
-bool RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
+status_t RpcSession::setupClient(
+ const std::function<status_t(const RpcAddress& sessionId, bool incoming)>& connectAndInit) {
{
std::lock_guard<std::mutex> _l(mMutex);
LOG_ALWAYS_FATAL_IF(mOutgoingConnections.size() != 0,
"Must only setup session once, but already has %zu clients",
mOutgoingConnections.size());
}
+ if (auto status = initShutdownTrigger(); status != OK) return status;
- if (!setupOneSocketConnection(addr, RpcAddress::zero(), false /*incoming*/)) return false;
+ if (status_t status = connectAndInit(RpcAddress::zero(), false /*incoming*/); status != OK)
+ return status;
{
ExclusiveConnection connection;
- status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
- ConnectionUse::CLIENT, &connection);
- if (status != OK) return false;
+ if (status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+ ConnectionUse::CLIENT, &connection);
+ status != OK)
+ return status;
uint32_t version;
- status = state()->readNewSessionResponse(connection.get(),
- sp<RpcSession>::fromExisting(this), &version);
- if (!setProtocolVersion(version)) return false;
+ if (status_t status =
+ state()->readNewSessionResponse(connection.get(),
+ sp<RpcSession>::fromExisting(this), &version);
+ status != OK)
+ return status;
+ if (!setProtocolVersion(version)) return BAD_VALUE;
}
// TODO(b/189955605): we should add additional sessions dynamically
// instead of all at once.
- // TODO(b/186470974): first risk of blocking
size_t numThreadsAvailable;
if (status_t status = getRemoteMaxThreads(&numThreadsAvailable); status != OK) {
- ALOGE("Could not get max threads after initial session to %s: %s", addr.toString().c_str(),
+ ALOGE("Could not get max threads after initial session setup: %s",
statusToString(status).c_str());
- return false;
+ return status;
}
if (status_t status = readId(); status != OK) {
- ALOGE("Could not get session id after initial session to %s; %s", addr.toString().c_str(),
+ ALOGE("Could not get session id after initial session setup: %s",
statusToString(status).c_str());
- return false;
- }
-
- // we've already setup one client
- for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
- // TODO(b/189955605): shutdown existing connections?
- if (!setupOneSocketConnection(addr, mId.value(), false /*incoming*/)) return false;
+ return status;
}
// TODO(b/189955605): we should add additional sessions dynamically
@@ -489,25 +449,38 @@
// requested to be set) in order to allow the other side to reliably make
// any requests at all.
- for (size_t i = 0; i < mMaxThreads; i++) {
- if (!setupOneSocketConnection(addr, mId.value(), true /*incoming*/)) return false;
+ // we've already setup one client
+ for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
+ if (status_t status = connectAndInit(mId.value(), false /*incoming*/); status != OK)
+ return status;
}
- return true;
+ for (size_t i = 0; i < mMaxThreads; i++) {
+ if (status_t status = connectAndInit(mId.value(), true /*incoming*/); status != OK)
+ return status;
+ }
+
+ return OK;
}
-bool RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, const RpcAddress& id,
- bool incoming) {
+status_t RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
+ return setupClient([&](const RpcAddress& sessionId, bool incoming) {
+ return setupOneSocketConnection(addr, sessionId, incoming);
+ });
+}
+
+status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr,
+ const RpcAddress& sessionId, bool incoming) {
for (size_t tries = 0; tries < 5; tries++) {
if (tries > 0) usleep(10000);
- unique_fd serverFd(
- TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ unique_fd serverFd(TEMP_FAILURE_RETRY(
+ socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
if (serverFd == -1) {
int savedErrno = errno;
ALOGE("Could not create socket at %s: %s", addr.toString().c_str(),
strerror(savedErrno));
- return false;
+ return -savedErrno;
}
if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
@@ -515,41 +488,87 @@
ALOGW("Connection reset on %s", addr.toString().c_str());
continue;
}
- int savedErrno = errno;
- ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
- strerror(savedErrno));
- return false;
+ if (errno != EAGAIN && errno != EINPROGRESS) {
+ int savedErrno = errno;
+ ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
+ strerror(savedErrno));
+ return -savedErrno;
+ }
+ // For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
+ // EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
+ status_t pollStatus = mShutdownTrigger->triggerablePoll(serverFd, POLLOUT);
+ if (pollStatus != OK) {
+ ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
+ statusToString(pollStatus).c_str());
+ return pollStatus;
+ }
+ int soError;
+ socklen_t soErrorLen = sizeof(soError);
+ int ret = getsockopt(serverFd.get(), SOL_SOCKET, SO_ERROR, &soError, &soErrorLen);
+ if (ret == -1) {
+ int savedErrno = errno;
+ ALOGE("Could not getsockopt() after connect() on non-blocking socket: %s",
+ strerror(savedErrno));
+ return -savedErrno;
+ }
+ if (soError != 0) {
+ ALOGE("After connect(), getsockopt() returns error for socket at %s: %s",
+ addr.toString().c_str(), strerror(soError));
+ return -soError;
+ }
}
-
- RpcConnectionHeader header{
- .version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
- .options = 0,
- };
- memcpy(&header.sessionId, &id.viewRawEmbedded(), sizeof(RpcWireAddress));
-
- if (incoming) header.options |= RPC_CONNECTION_OPTION_INCOMING;
-
- if (sizeof(header) != TEMP_FAILURE_RETRY(write(serverFd.get(), &header, sizeof(header)))) {
- int savedErrno = errno;
- ALOGE("Could not write connection header to socket at %s: %s", addr.toString().c_str(),
- strerror(savedErrno));
- return false;
- }
-
LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
- if (incoming) {
- return addIncomingConnection(std::move(serverFd));
- } else {
- return addOutgoingConnection(std::move(serverFd), true);
- }
+ return initAndAddConnection(std::move(serverFd), sessionId, incoming);
}
ALOGE("Ran out of retries to connect to %s", addr.toString().c_str());
- return false;
+ return UNKNOWN_ERROR;
}
-bool RpcSession::addIncomingConnection(unique_fd fd) {
+status_t RpcSession::initAndAddConnection(unique_fd fd, const RpcAddress& sessionId,
+ bool incoming) {
+ LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr);
+ auto ctx = mRpcTransportCtxFactory->newClientCtx();
+ if (ctx == nullptr) {
+ ALOGE("Unable to create client RpcTransportCtx with %s sockets",
+ mRpcTransportCtxFactory->toCString());
+ return NO_MEMORY;
+ }
+ auto server = ctx->newTransport(std::move(fd), mShutdownTrigger.get());
+ if (server == nullptr) {
+ ALOGE("Unable to set up RpcTransport in %s context", mRpcTransportCtxFactory->toCString());
+ return UNKNOWN_ERROR;
+ }
+
+ LOG_RPC_DETAIL("Socket at client with RpcTransport %p", server.get());
+
+ RpcConnectionHeader header{
+ .version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
+ .options = 0,
+ };
+ memcpy(&header.sessionId, &sessionId.viewRawEmbedded(), sizeof(RpcWireAddress));
+
+ if (incoming) header.options |= RPC_CONNECTION_OPTION_INCOMING;
+
+ auto sendHeaderStatus =
+ server->interruptableWriteFully(mShutdownTrigger.get(), &header, sizeof(header));
+ if (sendHeaderStatus != OK) {
+ ALOGE("Could not write connection header to socket: %s",
+ statusToString(sendHeaderStatus).c_str());
+ return sendHeaderStatus;
+ }
+
+ LOG_RPC_DETAIL("Socket at client: header sent");
+
+ if (incoming) {
+ return addIncomingConnection(std::move(server));
+ } else {
+ return addOutgoingConnection(std::move(server), true /*init*/);
+ }
+}
+
+status_t RpcSession::addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport) {
std::mutex mutex;
std::condition_variable joinCv;
std::unique_lock<std::mutex> lock(mutex);
@@ -558,13 +577,13 @@
bool ownershipTransferred = false;
thread = std::thread([&]() {
std::unique_lock<std::mutex> threadLock(mutex);
- unique_fd movedFd = std::move(fd);
+ std::unique_ptr<RpcTransport> movedRpcTransport = std::move(rpcTransport);
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
sp<RpcSession> session = thiz;
session->preJoinThreadOwnership(std::move(thread));
// only continue once we have a response or the connection fails
- auto setupResult = session->preJoinSetup(std::move(movedFd));
+ auto setupResult = session->preJoinSetup(std::move(movedRpcTransport));
ownershipTransferred = true;
threadLock.unlock();
@@ -575,23 +594,25 @@
});
joinCv.wait(lock, [&] { return ownershipTransferred; });
LOG_ALWAYS_FATAL_IF(!ownershipTransferred);
- return true;
+ return OK;
}
-bool RpcSession::addOutgoingConnection(unique_fd fd, bool init) {
+status_t RpcSession::initShutdownTrigger() {
+ // first client connection added, but setForServer not called, so
+ // initializaing for a client.
+ if (mShutdownTrigger == nullptr) {
+ mShutdownTrigger = FdTrigger::make();
+ mEventListener = mShutdownListener = sp<WaitForShutdownListener>::make();
+ if (mShutdownTrigger == nullptr) return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t RpcSession::addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport, bool init) {
sp<RpcConnection> connection = sp<RpcConnection>::make();
{
std::lock_guard<std::mutex> _l(mMutex);
-
- // first client connection added, but setForServer not called, so
- // initializaing for a client.
- if (mShutdownTrigger == nullptr) {
- mShutdownTrigger = FdTrigger::make();
- mEventListener = mShutdownListener = sp<WaitForShutdownListener>::make();
- if (mShutdownTrigger == nullptr) return false;
- }
-
- connection->fd = std::move(fd);
+ connection->rpcTransport = std::move(rpcTransport);
connection->exclusiveTid = gettid();
mOutgoingConnections.push_back(connection);
}
@@ -606,7 +627,7 @@
connection->exclusiveTid = std::nullopt;
}
- return status == OK;
+ return status;
}
bool RpcSession::setForServer(const wp<RpcServer>& server, const wp<EventListener>& eventListener,
@@ -626,9 +647,16 @@
return true;
}
-sp<RpcSession::RpcConnection> RpcSession::assignIncomingConnectionToThisThread(unique_fd fd) {
+sp<RpcSession::RpcConnection> RpcSession::assignIncomingConnectionToThisThread(
+ std::unique_ptr<RpcTransport> rpcTransport) {
std::lock_guard<std::mutex> _l(mMutex);
+ if (mIncomingConnections.size() >= mMaxThreads) {
+ ALOGE("Cannot add thread to session with %zu threads (max is set to %zu)",
+ mIncomingConnections.size(), mMaxThreads);
+ return nullptr;
+ }
+
// Don't accept any more connections, some have shutdown. Usually this
// happens when new connections are still being established as part of a
// very short-lived session which shuts down after it already started
@@ -638,7 +666,7 @@
}
sp<RpcConnection> session = sp<RpcConnection>::make();
- session->fd = std::move(fd);
+ session->rpcTransport = std::move(rpcTransport);
session->exclusiveTid = gettid();
mIncomingConnections.push_back(session);
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index f3406bb..b58f1b3 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -18,6 +18,7 @@
#include "RpcState.h"
+#include <android-base/hex.h>
#include <android-base/scopeguard.h>
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
@@ -272,8 +273,8 @@
status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, const char* what, const void* data,
size_t size) {
- LOG_RPC_DETAIL("Sending %s on fd %d: %s", what, connection->fd.get(),
- hexString(data, size).c_str());
+ LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+ android::base::HexString(data, size).c_str());
if (size > std::numeric_limits<ssize_t>::max()) {
ALOGE("Cannot send %s at size %zu (too big)", what, size);
@@ -281,11 +282,12 @@
return BAD_VALUE;
}
- if (status_t status = session->mShutdownTrigger->interruptableWriteFully(connection->fd.get(),
- data, size);
+ if (status_t status =
+ connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(),
+ data, size);
status != OK) {
- LOG_RPC_DETAIL("Failed to write %s (%zu bytes) on fd %d, error: %s", what, size,
- connection->fd.get(), statusToString(status).c_str());
+ LOG_RPC_DETAIL("Failed to write %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
+ connection->rpcTransport.get(), statusToString(status).c_str());
(void)session->shutdownAndWait(false);
return status;
}
@@ -303,15 +305,16 @@
}
if (status_t status =
- session->mShutdownTrigger->interruptableReadFully(connection->fd.get(), data, size);
+ connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.get(),
+ data, size);
status != OK) {
- LOG_RPC_DETAIL("Failed to read %s (%zu bytes) on fd %d, error: %s", what, size,
- connection->fd.get(), statusToString(status).c_str());
+ LOG_RPC_DETAIL("Failed to read %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
+ connection->rpcTransport.get(), statusToString(status).c_str());
return status;
}
- LOG_RPC_DETAIL("Received %s on fd %d: %s", what, connection->fd.get(),
- hexString(data, size).c_str());
+ LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+ android::base::HexString(data, size).c_str());
return OK;
}
@@ -489,7 +492,8 @@
return status;
if (flags & IBinder::FLAG_ONEWAY) {
- LOG_RPC_DETAIL("Oneway command, so no longer waiting on %d", connection->fd.get());
+ LOG_RPC_DETAIL("Oneway command, so no longer waiting on RpcTransport %p",
+ connection->rpcTransport.get());
// Do not wait on result.
// However, too many oneway calls may cause refcounts to build up and fill up the socket,
@@ -584,7 +588,7 @@
status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, CommandType type) {
- LOG_RPC_DETAIL("getAndExecuteCommand on fd %d", connection->fd.get());
+ LOG_RPC_DETAIL("getAndExecuteCommand on RpcTransport %p", connection->rpcTransport.get());
RpcWireHeader command;
if (status_t status = rpcRec(connection, session, "command header", &command, sizeof(command));
@@ -597,8 +601,7 @@
status_t RpcState::drainCommands(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, CommandType type) {
uint8_t buf;
- while (0 < TEMP_FAILURE_RETRY(
- recv(connection->fd.get(), &buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT))) {
+ while (connection->rpcTransport->peek(&buf, sizeof(buf)).value_or(0) > 0) {
status_t status = getAndExecuteCommand(connection, session, type);
if (status != OK) return status;
}
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
new file mode 100644
index 0000000..d77fc52
--- /dev/null
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RpcRawTransport"
+#include <log/log.h>
+
+#include <poll.h>
+
+#include <binder/RpcTransportRaw.h>
+
+#include "FdTrigger.h"
+#include "RpcState.h"
+
+using android::base::ErrnoError;
+using android::base::Result;
+
+namespace android {
+
+namespace {
+
+// RpcTransport with TLS disabled.
+class RpcTransportRaw : public RpcTransport {
+public:
+ explicit RpcTransportRaw(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
+ Result<size_t> send(const void* buf, size_t size) {
+ ssize_t ret = TEMP_FAILURE_RETRY(::send(mSocket.get(), buf, size, MSG_NOSIGNAL));
+ if (ret < 0) {
+ return ErrnoError() << "send()";
+ }
+ return ret;
+ }
+ Result<size_t> recv(void* buf, size_t size) {
+ ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_NOSIGNAL));
+ if (ret < 0) {
+ return ErrnoError() << "recv()";
+ }
+ return ret;
+ }
+ Result<size_t> peek(void *buf, size_t size) override {
+ ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_PEEK));
+ if (ret < 0) {
+ return ErrnoError() << "recv(MSG_PEEK)";
+ }
+ return ret;
+ }
+
+ status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size) override {
+ const uint8_t* buffer = reinterpret_cast<const uint8_t*>(data);
+ const uint8_t* end = buffer + size;
+
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ status_t status;
+ while ((status = fdTrigger->triggerablePoll(mSocket.get(), POLLOUT)) == OK) {
+ auto writeSize = this->send(buffer, end - buffer);
+ if (!writeSize.ok()) {
+ LOG_RPC_DETAIL("RpcTransport::send(): %s", writeSize.error().message().c_str());
+ return writeSize.error().code() == 0 ? UNKNOWN_ERROR : -writeSize.error().code();
+ }
+
+ if (*writeSize == 0) return DEAD_OBJECT;
+
+ buffer += *writeSize;
+ if (buffer == end) return OK;
+ }
+ return status;
+ }
+
+ status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) override {
+ uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
+ uint8_t* end = buffer + size;
+
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ status_t status;
+ while ((status = fdTrigger->triggerablePoll(mSocket.get(), POLLIN)) == OK) {
+ auto readSize = this->recv(buffer, end - buffer);
+ if (!readSize.ok()) {
+ LOG_RPC_DETAIL("RpcTransport::recv(): %s", readSize.error().message().c_str());
+ return readSize.error().code() == 0 ? UNKNOWN_ERROR : -readSize.error().code();
+ }
+
+ if (*readSize == 0) return DEAD_OBJECT; // EOF
+
+ buffer += *readSize;
+ if (buffer == end) return OK;
+ }
+ return status;
+ }
+
+private:
+ android::base::unique_fd mSocket;
+};
+
+// RpcTransportCtx with TLS disabled.
+class RpcTransportCtxRaw : public RpcTransportCtx {
+public:
+ std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd, FdTrigger*) const {
+ return std::make_unique<RpcTransportRaw>(std::move(fd));
+ }
+};
+} // namespace
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryRaw::newServerCtx() const {
+ return std::make_unique<RpcTransportCtxRaw>();
+}
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryRaw::newClientCtx() const {
+ return std::make_unique<RpcTransportCtxRaw>();
+}
+
+const char *RpcTransportCtxFactoryRaw::toCString() const {
+ return "raw";
+}
+
+std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryRaw::make() {
+ return std::unique_ptr<RpcTransportCtxFactoryRaw>(new RpcTransportCtxFactoryRaw());
+}
+
+} // namespace android
diff --git a/libs/binder/ServiceManagerHost.cpp b/libs/binder/ServiceManagerHost.cpp
index 1c2f9b4..59334b7 100644
--- a/libs/binder/ServiceManagerHost.cpp
+++ b/libs/binder/ServiceManagerHost.cpp
@@ -158,8 +158,10 @@
LOG_ALWAYS_FATAL_IF(!forwardResult->hostPort().has_value());
auto rpcSession = RpcSession::make();
- if (!rpcSession->setupInetClient("127.0.0.1", *forwardResult->hostPort())) {
- ALOGE("Unable to set up inet client on host port %u", *forwardResult->hostPort());
+ if (status_t status = rpcSession->setupInetClient("127.0.0.1", *forwardResult->hostPort());
+ status != OK) {
+ ALOGE("Unable to set up inet client on host port %u: %s", *forwardResult->hostPort(),
+ statusToString(status).c_str());
return nullptr;
}
auto binder = rpcSession->getRootObject();
diff --git a/libs/binder/Utils.cpp b/libs/binder/Utils.cpp
index 90a4502..d2a5be1 100644
--- a/libs/binder/Utils.cpp
+++ b/libs/binder/Utils.cpp
@@ -18,10 +18,24 @@
#include <string.h>
+using android::base::ErrnoError;
+using android::base::Result;
+
namespace android {
void zeroMemory(uint8_t* data, size_t size) {
memset(data, 0, size);
}
-} // namespace android
+Result<void> setNonBlocking(android::base::borrowed_fd fd) {
+ int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL));
+ if (flags == -1) {
+ return ErrnoError() << "Could not get flags for fd";
+ }
+ if (int ret = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_SETFL, flags | O_NONBLOCK)); ret == -1) {
+ return ErrnoError() << "Could not set non-blocking flag for fd";
+ }
+ return {};
+}
+
+} // namespace android
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index f94b158..1e383da 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -17,9 +17,14 @@
#include <cstdint>
#include <stddef.h>
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+
namespace android {
// avoid optimizations
void zeroMemory(uint8_t* data, size_t size);
+android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);
+
} // namespace android
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 40ff78c..bf3e7e0 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -19,6 +19,7 @@
#include <binder/IBinder.h>
#include <binder/RpcAddress.h>
#include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -31,6 +32,7 @@
namespace android {
+class FdTrigger;
class RpcSocketAddress;
/**
@@ -47,7 +49,8 @@
*/
class RpcServer final : public virtual RefBase, private RpcSession::EventListener {
public:
- static sp<RpcServer> make();
+ static sp<RpcServer> make(
+ std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
/**
* This represents a session for responses, e.g.:
@@ -57,12 +60,12 @@
* process B makes binder b and sends it to A
* A uses this 'back session' to send things back to B
*/
- [[nodiscard]] bool setupUnixDomainServer(const char* path);
+ [[nodiscard]] status_t setupUnixDomainServer(const char* path);
/**
* Creates an RPC server at the current port.
*/
- [[nodiscard]] bool setupVsockServer(unsigned int port);
+ [[nodiscard]] status_t setupVsockServer(unsigned int port);
/**
* Creates an RPC server at the current port using IPv4.
@@ -72,8 +75,14 @@
* 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.
+ *
+ * Set the IPv4 address for the socket to be listening on.
+ * "127.0.0.1" allows for local connections from the same device.
+ * "0.0.0.0" allows for connections on any IP address that the device may
+ * have
*/
- [[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort);
+ [[nodiscard]] status_t setupInetServer(const char* address, unsigned int port,
+ unsigned int* assignedPort);
/**
* If setup*Server has been successful, return true. Otherwise return false.
@@ -89,7 +98,7 @@
* Set up server using an external FD previously set up by releaseServer().
* Return false if there's already a server.
*/
- bool setupExternalServer(base::unique_fd serverFd);
+ [[nodiscard]] status_t setupExternalServer(base::unique_fd serverFd);
void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
@@ -161,14 +170,15 @@
private:
friend sp<RpcServer>;
- RpcServer();
+ explicit RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
void onSessionIncomingThreadEnded() override;
static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd);
- bool setupSocketServer(const RpcSocketAddress& address);
+ status_t setupSocketServer(const RpcSocketAddress& address);
+ const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
bool mAgreedExperimental = false;
size_t mMaxThreads = 1;
std::optional<uint32_t> mProtocolVersion;
@@ -181,8 +191,9 @@
sp<IBinder> mRootObject;
wp<IBinder> mRootObjectWeak;
std::map<RpcAddress, sp<RpcSession>> mSessions;
- std::unique_ptr<RpcSession::FdTrigger> mShutdownTrigger;
+ std::unique_ptr<FdTrigger> mShutdownTrigger;
std::condition_variable mShutdownCv;
+ std::unique_ptr<RpcTransportCtx> mCtx;
};
} // namespace android
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 1f7c029..761c50d 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -18,6 +18,8 @@
#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
#include <binder/RpcAddress.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -36,6 +38,8 @@
class RpcServer;
class RpcSocketAddress;
class RpcState;
+class RpcTransport;
+class FdTrigger;
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 0;
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000;
@@ -48,7 +52,8 @@
*/
class RpcSession final : public virtual RefBase {
public:
- static sp<RpcSession> make();
+ static sp<RpcSession> make(
+ std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
/**
* Set the maximum number of threads allowed to be made (for things like callbacks).
@@ -74,17 +79,30 @@
* This should be called once per thread, matching 'join' in the remote
* process.
*/
- [[nodiscard]] bool setupUnixDomainClient(const char* path);
+ [[nodiscard]] status_t setupUnixDomainClient(const char* path);
/**
* Connects to an RPC server at the CVD & port.
*/
- [[nodiscard]] bool setupVsockClient(unsigned int cvd, unsigned int port);
+ [[nodiscard]] status_t setupVsockClient(unsigned int cvd, unsigned int port);
/**
* Connects to an RPC server at the given address and port.
*/
- [[nodiscard]] bool setupInetClient(const char* addr, unsigned int port);
+ [[nodiscard]] status_t setupInetClient(const char* addr, unsigned int port);
+
+ /**
+ * Starts talking to an RPC server which has already been connected to. This
+ * is expected to be used when another process has permission to connect to
+ * a binder RPC service, but this process only has permission to talk to
+ * that service.
+ *
+ * For convenience, if 'fd' is -1, 'request' will be called.
+ *
+ * For future compatibility, 'request' should not reference any stack data.
+ */
+ [[nodiscard]] status_t setupPreconnectedClient(base::unique_fd fd,
+ std::function<base::unique_fd()>&& request);
/**
* For debugging!
@@ -93,7 +111,7 @@
* response will never be satisfied. All data sent here will be
* unceremoniously cast down the bottomless pit, /dev/null.
*/
- [[nodiscard]] bool addNullDebuggingClient();
+ [[nodiscard]] status_t addNullDebuggingClient();
/**
* Query the other side of the session for the root object hosted by that
@@ -142,49 +160,7 @@
friend sp<RpcSession>;
friend RpcServer;
friend RpcState;
- RpcSession();
-
- /** This is not a pipe. */
- struct FdTrigger {
- /** Returns nullptr for error case */
- static std::unique_ptr<FdTrigger> make();
-
- /**
- * Close the write end of the pipe so that the read end receives POLLHUP.
- * Not threadsafe.
- */
- void trigger();
-
- /**
- * Whether this has been triggered.
- */
- bool isTriggered();
-
- /**
- * Poll for a read event.
- *
- * event - for pollfd
- *
- * Return:
- * true - time to read!
- * false - trigger happened
- */
- status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
-
- /**
- * Read (or write), but allow to be interrupted by this trigger.
- *
- * Return:
- * true - succeeded in completely processing 'size'
- * false - interrupted (failure or trigger)
- */
- status_t interruptableReadFully(base::borrowed_fd fd, void* data, size_t size);
- status_t interruptableWriteFully(base::borrowed_fd fd, const void* data, size_t size);
-
- private:
- base::unique_fd mWrite;
- base::unique_fd mRead;
- };
+ explicit RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
class EventListener : public virtual RefBase {
public:
@@ -204,7 +180,7 @@
};
struct RpcConnection : public RefBase {
- base::unique_fd fd;
+ std::unique_ptr<RpcTransport> rpcTransport;
// whether this or another thread is currently using this fd to make
// or receive transactions.
@@ -230,21 +206,30 @@
// Status of setup
status_t status;
};
- PreJoinSetupResult preJoinSetup(base::unique_fd fd);
+ PreJoinSetupResult preJoinSetup(std::unique_ptr<RpcTransport> rpcTransport);
// join on thread passed to preJoinThreadOwnership
static void join(sp<RpcSession>&& session, PreJoinSetupResult&& result);
- [[nodiscard]] bool setupSocketClient(const RpcSocketAddress& address);
- [[nodiscard]] bool setupOneSocketConnection(const RpcSocketAddress& address,
- const RpcAddress& sessionId, bool server);
- [[nodiscard]] bool addIncomingConnection(base::unique_fd fd);
- [[nodiscard]] bool addOutgoingConnection(base::unique_fd fd, bool init);
+ [[nodiscard]] status_t setupClient(
+ const std::function<status_t(const RpcAddress& sessionId, bool incoming)>&
+ connectAndInit);
+ [[nodiscard]] status_t setupSocketClient(const RpcSocketAddress& address);
+ [[nodiscard]] status_t setupOneSocketConnection(const RpcSocketAddress& address,
+ const RpcAddress& sessionId, bool incoming);
+ [[nodiscard]] status_t initAndAddConnection(base::unique_fd fd, const RpcAddress& sessionId,
+ bool incoming);
+ [[nodiscard]] status_t addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport);
+ [[nodiscard]] status_t addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport,
+ bool init);
[[nodiscard]] bool setForServer(const wp<RpcServer>& server,
const wp<RpcSession::EventListener>& eventListener,
const RpcAddress& sessionId);
- sp<RpcConnection> assignIncomingConnectionToThisThread(base::unique_fd fd);
+ sp<RpcConnection> assignIncomingConnectionToThisThread(
+ std::unique_ptr<RpcTransport> rpcTransport);
[[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
+ status_t initShutdownTrigger();
+
enum class ConnectionUse {
CLIENT,
CLIENT_ASYNC,
@@ -275,6 +260,8 @@
bool mReentrant = false;
};
+ const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
+
// On the other side of a session, for each of mOutgoingConnections here, there should
// be one of mIncomingConnections on the other side (and vice versa).
//
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
new file mode 100644
index 0000000..1b69519
--- /dev/null
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+// Wraps the transport layer of RPC. Implementation may use plain sockets or TLS.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class FdTrigger;
+
+// Represents a socket connection.
+class RpcTransport {
+public:
+ virtual ~RpcTransport() = default;
+
+ // replacement of ::recv(MSG_PEEK). Error code may not be set if TLS is enabled.
+ virtual android::base::Result<size_t> peek(void *buf, size_t size) = 0;
+
+ /**
+ * Read (or write), but allow to be interrupted by a trigger.
+ *
+ * Return:
+ * OK - succeeded in completely processing 'size'
+ * error - interrupted (failure or trigger)
+ */
+ virtual status_t interruptableWriteFully(FdTrigger *fdTrigger, const void *buf,
+ size_t size) = 0;
+ virtual status_t interruptableReadFully(FdTrigger *fdTrigger, void *buf, size_t size) = 0;
+
+protected:
+ RpcTransport() = default;
+};
+
+// Represents the context that generates the socket connection.
+class RpcTransportCtx {
+public:
+ virtual ~RpcTransportCtx() = default;
+
+ // Create a new RpcTransport object.
+ //
+ // Implemenion details: for TLS, this function may incur I/O. |fdTrigger| may be used
+ // to interrupt I/O. This function blocks until handshake is finished.
+ [[nodiscard]] virtual std::unique_ptr<RpcTransport> newTransport(
+ android::base::unique_fd fd, FdTrigger *fdTrigger) const = 0;
+
+protected:
+ RpcTransportCtx() = default;
+};
+
+// A factory class that generates RpcTransportCtx.
+class RpcTransportCtxFactory {
+public:
+ virtual ~RpcTransportCtxFactory() = default;
+ // Creates server context.
+ [[nodiscard]] virtual std::unique_ptr<RpcTransportCtx> newServerCtx() const = 0;
+
+ // Creates client context.
+ [[nodiscard]] virtual std::unique_ptr<RpcTransportCtx> newClientCtx() const = 0;
+
+ // Return a short description of this transport (e.g. "raw"). For logging / debugging / testing
+ // only.
+ [[nodiscard]] virtual const char *toCString() const = 0;
+
+protected:
+ RpcTransportCtxFactory() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcTransportRaw.h b/libs/binder/include/binder/RpcTransportRaw.h
new file mode 100644
index 0000000..6fb1f92
--- /dev/null
+++ b/libs/binder/include/binder/RpcTransportRaw.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+// Wraps the transport layer of RPC. Implementation uses plain sockets.
+// Note: don't use directly. You probably want newServerRpcTransportCtx / newClientRpcTransportCtx.
+
+#pragma once
+
+#include <memory>
+
+#include <binder/RpcTransport.h>
+
+namespace android {
+
+// RpcTransportCtxFactory with TLS disabled.
+class RpcTransportCtxFactoryRaw : public RpcTransportCtxFactory {
+public:
+ static std::unique_ptr<RpcTransportCtxFactory> make();
+
+ std::unique_ptr<RpcTransportCtx> newServerCtx() const override;
+ std::unique_ptr<RpcTransportCtx> newClientCtx() const override;
+ const char* toCString() const override;
+
+private:
+ RpcTransportCtxFactoryRaw() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 68ec669..bcb13ae 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -19,16 +19,20 @@
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+using android::OK;
using android::RpcServer;
using android::RpcSession;
+using android::status_t;
+using android::statusToString;
extern "C" {
bool RunRpcServer(AIBinder* service, unsigned int port) {
auto server = RpcServer::make();
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
- if (!server->setupVsockServer(port)) {
- LOG(ERROR) << "Failed to set up vsock server with port " << port;
+ if (status_t status = server->setupVsockServer(port); status != OK) {
+ LOG(ERROR) << "Failed to set up vsock server with port " << port
+ << " error: " << statusToString(status).c_str();
return false;
}
server->setRootObject(AIBinder_toPlatformBinder(service));
@@ -41,8 +45,9 @@
AIBinder* RpcClient(unsigned int cid, unsigned int port) {
auto session = RpcSession::make();
- if (!session->setupVsockClient(cid, port)) {
- LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port;
+ if (status_t status = session->setupVsockClient(cid, port); status != OK) {
+ LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port
+ << " error: " << statusToString(status).c_str();
return nullptr;
}
return AIBinder_fromPlatformBinder(session->getRootObject());
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 6c44726..5de64f8 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -55,6 +55,12 @@
std::call_once(mFlagThis, [&]() {
__assert(__FILE__, __LINE__, "SharedRefBase: no ref created during lifetime");
});
+
+ if (ref() != nullptr) {
+ __assert(__FILE__, __LINE__,
+ "SharedRefBase: destructed but still able to lock weak_ptr. Is this object "
+ "double-owned?");
+ }
}
/**
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 5ad390e..b5c06e9 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -224,6 +224,17 @@
return true;
}
+TEST(NdkBinder, DetectDoubleOwn) {
+ auto badService = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
+ EXPECT_DEATH(std::shared_ptr<MyBinderNdkUnitTest>(badService.get()),
+ "Is this object double-owned?");
+}
+
+TEST(NdkBinder, DetectNoSharedRefBaseCreated) {
+ EXPECT_DEATH(std::make_shared<MyBinderNdkUnitTest>(),
+ "SharedRefBase: no ref created during lifetime");
+}
+
TEST(NdkBinder, GetServiceThatDoesntExist) {
sp<IFoo> foo = IFoo::getService("asdfghkl;");
EXPECT_EQ(nullptr, foo.get());
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 20e9178..179b7c8 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -23,7 +23,7 @@
use crate::sys;
use std::fs::File;
-use std::os::unix::io::{AsRawFd, FromRawFd};
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
/// Rust version of the Java class android.os.ParcelFileDescriptor
#[derive(Debug)]
@@ -48,6 +48,12 @@
}
}
+impl AsRawFd for ParcelFileDescriptor {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_fd()
+ }
+}
+
impl Serialize for ParcelFileDescriptor {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
let fd = self.0.as_raw_fd();
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 0bff2a7..9811cdf 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -36,6 +36,7 @@
using android::OK;
using android::RpcServer;
using android::sp;
+using android::status_t;
using android::statusToString;
using android::String16;
using android::base::Basename;
@@ -50,6 +51,7 @@
namespace {
+const char* kLocalInetAddress = "127.0.0.1";
using ServiceRetriever = decltype(&android::IServiceManager::checkService);
using android::debug::IAdbManager;
@@ -90,8 +92,8 @@
}
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
- if (!rpcServer->setupInetServer(0, &port)) {
- LOG(ERROR) << "setupInetServer failed";
+ if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
+ LOG(ERROR) << "setupInetServer failed: " << statusToString(status);
return EX_SOFTWARE;
}
auto socket = rpcServer->releaseServer();
@@ -203,8 +205,8 @@
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
rpcServer->setRootObject(service);
unsigned int port;
- if (!rpcServer->setupInetServer(0, &port)) {
- LOG(ERROR) << "Unable to set up inet server";
+ if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
+ LOG(ERROR) << "Unable to set up inet server: " << statusToString(status);
return EX_SOFTWARE;
}
LOG(INFO) << "Finish wrapping servicemanager with RPC on port " << port;
diff --git a/libs/binder/tests/IBinderRpcBenchmark.aidl b/libs/binder/tests/IBinderRpcBenchmark.aidl
index 1457422..2baf680 100644
--- a/libs/binder/tests/IBinderRpcBenchmark.aidl
+++ b/libs/binder/tests/IBinderRpcBenchmark.aidl
@@ -17,4 +17,5 @@
interface IBinderRpcBenchmark {
@utf8InCpp String repeatString(@utf8InCpp String str);
IBinder repeatBinder(IBinder binder);
+ byte[] repeatBytes(in byte[] bytes);
}
diff --git a/libs/binder/tests/binderClearBufTest.cpp b/libs/binder/tests/binderClearBufTest.cpp
index 2d30c8d..307151c 100644
--- a/libs/binder/tests/binderClearBufTest.cpp
+++ b/libs/binder/tests/binderClearBufTest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/hex.h>
#include <android-base/logging.h>
#include <binder/Binder.h>
#include <binder/IBinder.h>
@@ -30,22 +31,6 @@
const String16 kServerName = String16("binderClearBuf");
-std::string hexString(const void* bytes, size_t len) {
- if (bytes == nullptr) return "<null>";
-
- const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
- char chars[] = "0123456789abcdef";
- std::string result;
- result.resize(len * 2);
-
- for (size_t i = 0; i < len; i++) {
- result[2 * i] = chars[bytes8[i] >> 4];
- result[2 * i + 1] = chars[bytes8[i] & 0xf];
- }
-
- return result;
-}
-
class FooBar : public BBinder {
public:
enum {
@@ -83,7 +68,7 @@
lastReply = reply.data();
lastReplySize = reply.dataSize();
}
- *outBuffer = hexString(lastReply, lastReplySize);
+ *outBuffer = android::base::HexString(lastReply, lastReplySize);
return result;
}
};
diff --git a/libs/binder/tests/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp
index 5dd9212..3f72b8f 100644
--- a/libs/binder/tests/binderHostDeviceTest.cpp
+++ b/libs/binder/tests/binderHostDeviceTest.cpp
@@ -101,8 +101,9 @@
[[nodiscard]] static sp<IBinder> get(unsigned int hostPort) {
auto rpcSession = RpcSession::make();
- if (!rpcSession->setupInetClient("127.0.0.1", hostPort)) {
- ADD_FAILURE() << "Failed to setupInetClient on " << hostPort;
+ if (status_t status = rpcSession->setupInetClient("127.0.0.1", hostPort); status != OK) {
+ ADD_FAILURE() << "Failed to setupInetClient on " << hostPort << ": "
+ << statusToString(status);
return nullptr;
}
return rpcSession->getRootObject();
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 4c3225f..eea7d8c 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1192,8 +1192,8 @@
if (rpcServer == nullptr) return {};
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
- if (!rpcServer->setupInetServer(0, &port)) {
- ADD_FAILURE() << "setupInetServer failed";
+ if (status_t status = rpcServer->setupInetServer("127.0.0.1", 0, &port); status != OK) {
+ ADD_FAILURE() << "setupInetServer failed" << statusToString(status);
return {};
}
return {rpcServer->releaseServer(), port};
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index 5f4a7b5..0c452ff 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -42,6 +42,8 @@
using android::RpcServer;
using android::RpcSession;
using android::sp;
+using android::status_t;
+using android::statusToString;
using android::String16;
using android::binder::Status;
@@ -50,8 +52,12 @@
*out = str;
return Status::ok();
}
- Status repeatBinder(const sp<IBinder>& str, sp<IBinder>* out) override {
- *out = str;
+ Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
+ *out = binder;
+ return Status::ok();
+ }
+ Status repeatBytes(const std::vector<uint8_t>& bytes, std::vector<uint8_t>* out) override {
+ *out = bytes;
return Status::ok();
}
};
@@ -61,12 +67,11 @@
RPC,
};
-static void EachTransport(benchmark::internal::Benchmark* b) {
+static const std::initializer_list<int64_t> kTransportList = {
#ifdef __BIONIC__
- b->Args({Transport::KERNEL});
+ Transport::KERNEL,
#endif
- b->Args({Transport::RPC});
-}
+ Transport::RPC};
static sp<RpcSession> gSession = RpcSession::make();
#ifdef __BIONIC__
@@ -96,9 +101,9 @@
CHECK_EQ(OK, binder->pingBinder());
}
}
-BENCHMARK(BM_pingTransaction)->Apply(EachTransport);
+BENCHMARK(BM_pingTransaction)->ArgsProduct({kTransportList});
-void BM_repeatString(benchmark::State& state) {
+void BM_repeatTwoPageString(benchmark::State& state) {
sp<IBinder> binder = getBinderForOptions(state);
sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
@@ -125,7 +130,27 @@
CHECK(ret.isOk()) << ret;
}
}
-BENCHMARK(BM_repeatString)->Apply(EachTransport);
+BENCHMARK(BM_repeatTwoPageString)->ArgsProduct({kTransportList});
+
+void BM_throughputForTransportAndBytes(benchmark::State& state) {
+ sp<IBinder> binder = getBinderForOptions(state);
+ sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
+ CHECK(iface != nullptr);
+
+ std::vector<uint8_t> bytes = std::vector<uint8_t>(state.range(1));
+ for (size_t i = 0; i < bytes.size(); i++) {
+ bytes[i] = i % 256;
+ }
+
+ while (state.KeepRunning()) {
+ std::vector<uint8_t> out;
+ Status ret = iface->repeatBytes(bytes, &out);
+ CHECK(ret.isOk()) << ret;
+ }
+}
+BENCHMARK(BM_throughputForTransportAndBytes)
+ ->ArgsProduct({kTransportList,
+ {64, 1024, 2048, 4096, 8182, 16364, 32728, 65535, 65536, 65537}});
void BM_repeatBinder(benchmark::State& state) {
sp<IBinder> binder = gSession->getRootObject();
@@ -142,7 +167,7 @@
CHECK(ret.isOk()) << ret;
}
}
-BENCHMARK(BM_repeatBinder)->Apply(EachTransport);
+BENCHMARK(BM_repeatBinder)->ArgsProduct({kTransportList});
int main(int argc, char** argv) {
::benchmark::Initialize(&argc, argv);
@@ -152,15 +177,15 @@
(void)unlink(addr.c_str());
std::cerr << "Tests suffixes:" << std::endl;
- std::cerr << "\t\\" << Transport::KERNEL << " is KERNEL" << std::endl;
- std::cerr << "\t\\" << Transport::RPC << " is RPC" << std::endl;
+ std::cerr << "\t.../" << Transport::KERNEL << " is KERNEL" << std::endl;
+ std::cerr << "\t.../" << Transport::RPC << " is RPC" << std::endl;
if (0 == fork()) {
prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
sp<RpcServer> server = RpcServer::make();
server->setRootObject(sp<MyBinderRpcBenchmark>::make());
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
- CHECK(server->setupUnixDomainServer(addr.c_str()));
+ CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
server->join();
exit(1);
}
@@ -182,11 +207,13 @@
CHECK_NE(nullptr, gKernelBinder.get());
#endif
+ status_t status;
for (size_t tries = 0; tries < 5; tries++) {
usleep(10000);
- if (gSession->setupUnixDomainClient(addr.c_str())) goto success;
+ status = gSession->setupUnixDomainClient(addr.c_str());
+ if (status == OK) goto success;
}
- LOG(FATAL) << "Could not connect.";
+ LOG(FATAL) << "Could not connect: " << statusToString(status).c_str();
success:
::benchmark::RunSpecifiedBenchmarks();
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index d5786bc..15ccae9 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -29,6 +29,8 @@
#include <binder/ProcessState.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
+#include <binder/RpcTransportRaw.h>
#include <gtest/gtest.h>
#include <chrono>
@@ -40,6 +42,7 @@
#include <sys/prctl.h>
#include <unistd.h>
+#include "../RpcSocketAddress.h" // for testing preconnected clients
#include "../RpcState.h" // for debugging
#include "../vm_sockets.h" // for VMADDR_*
@@ -49,6 +52,22 @@
static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+const char* kLocalInetAddress = "127.0.0.1";
+
+enum class RpcSecurity { RAW };
+
+static inline std::vector<RpcSecurity> RpcSecurityValues() {
+ return {RpcSecurity::RAW};
+}
+
+static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(RpcSecurity rpcSecurity) {
+ switch (rpcSecurity) {
+ case RpcSecurity::RAW:
+ return RpcTransportCtxFactoryRaw::make();
+ default:
+ LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
+ }
+}
TEST(BinderRpcParcel, EntireParcelFormatted) {
Parcel p;
@@ -57,13 +76,20 @@
EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
}
-TEST(BinderRpc, SetExternalServer) {
+class BinderRpcSimple : public ::testing::TestWithParam<RpcSecurity> {
+public:
+ static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) {
+ return newFactory(info.param)->toCString();
+ }
+};
+
+TEST_P(BinderRpcSimple, SetExternalServerTest) {
base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
int sinkFd = sink.get();
- auto server = RpcServer::make();
+ auto server = RpcServer::make(newFactory(GetParam()));
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
ASSERT_FALSE(server->hasServer());
- ASSERT_TRUE(server->setupExternalServer(std::move(sink)));
+ ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
ASSERT_TRUE(server->hasServer());
base::unique_fd retrieved = server->releaseServer();
ASSERT_FALSE(server->hasServer());
@@ -384,12 +410,15 @@
};
enum class SocketType {
+ PRECONNECTED,
UNIX,
VSOCK,
INET,
};
-static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) {
- switch (info.param) {
+static inline std::string PrintToString(SocketType socketType) {
+ switch (socketType) {
+ case SocketType::PRECONNECTED:
+ return "preconnected_uds";
case SocketType::UNIX:
return "unix_domain_socket";
case SocketType::VSOCK:
@@ -402,7 +431,21 @@
}
}
-class BinderRpc : public ::testing::TestWithParam<SocketType> {
+static base::unique_fd connectToUds(const char* addrStr) {
+ UnixSocketAddress addr(addrStr);
+ base::unique_fd serverFd(
+ TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ int savedErrno = errno;
+ CHECK(serverFd.ok()) << "Could not create socket " << addrStr << ": " << strerror(savedErrno);
+
+ if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
+ int savedErrno = errno;
+ LOG(FATAL) << "Could not connect to socket " << addrStr << ": " << strerror(savedErrno);
+ }
+ return serverFd;
+}
+
+class BinderRpc : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity>> {
public:
struct Options {
size_t numThreads = 1;
@@ -410,13 +453,19 @@
size_t numIncomingConnections = 0;
};
+ static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ auto [type, security] = info.param;
+ return PrintToString(type) + "_" + newFactory(security)->toCString();
+ }
+
// This creates a new process serving an interface on a certain number of
// threads.
ProcessSession createRpcTestSocketServerProcess(
const Options& options, const std::function<void(const sp<RpcServer>&)>& configure) {
CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
- SocketType socketType = GetParam();
+ SocketType socketType = std::get<0>(GetParam());
+ RpcSecurity rpcSecurity = std::get<1>(GetParam());
unsigned int vsockPort = allocateVsockPort();
std::string addr = allocateSocketAddress();
@@ -424,7 +473,7 @@
auto ret = ProcessSession{
.host = Process([&](android::base::borrowed_fd writeEnd) {
- sp<RpcServer> server = RpcServer::make();
+ sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity));
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
server->setMaxThreads(options.numThreads);
@@ -432,14 +481,16 @@
unsigned int outPort = 0;
switch (socketType) {
+ case SocketType::PRECONNECTED:
+ [[fallthrough]];
case SocketType::UNIX:
- CHECK(server->setupUnixDomainServer(addr.c_str())) << addr;
+ CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str())) << addr;
break;
case SocketType::VSOCK:
- CHECK(server->setupVsockServer(vsockPort));
+ CHECK_EQ(OK, server->setupVsockServer(vsockPort));
break;
case SocketType::INET: {
- CHECK(server->setupInetServer(0, &outPort));
+ CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
CHECK_NE(0, outPort);
break;
}
@@ -465,24 +516,35 @@
CHECK_NE(0, outPort);
}
+ status_t status;
+
for (size_t i = 0; i < options.numSessions; i++) {
- sp<RpcSession> session = RpcSession::make();
+ sp<RpcSession> session = RpcSession::make(newFactory(rpcSecurity));
session->setMaxThreads(options.numIncomingConnections);
switch (socketType) {
+ case SocketType::PRECONNECTED:
+ status = session->setupPreconnectedClient({}, [=]() {
+ return connectToUds(addr.c_str());
+ });
+ if (status == OK) goto success;
+ break;
case SocketType::UNIX:
- if (session->setupUnixDomainClient(addr.c_str())) goto success;
+ status = session->setupUnixDomainClient(addr.c_str());
+ if (status == OK) goto success;
break;
case SocketType::VSOCK:
- if (session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
+ status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
+ if (status == OK) goto success;
break;
case SocketType::INET:
- if (session->setupInetClient("127.0.0.1", outPort)) goto success;
+ status = session->setupInetClient("127.0.0.1", outPort);
+ if (status == OK) goto success;
break;
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
- LOG_ALWAYS_FATAL("Could not connect");
+ LOG_ALWAYS_FATAL("Could not connect %s", statusToString(status).c_str());
success:
ret.sessions.push_back({session, session->getRootObject()});
}
@@ -1130,21 +1192,27 @@
}
static bool testSupportVsockLoopback() {
+ // We don't need to enable TLS to know if vsock is supported.
unsigned int vsockPort = allocateVsockPort();
- sp<RpcServer> server = RpcServer::make();
+ sp<RpcServer> server = RpcServer::make(RpcTransportCtxFactoryRaw::make());
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
- CHECK(server->setupVsockServer(vsockPort));
+ if (status_t status = server->setupVsockServer(vsockPort); status != OK) {
+ if (status == -EAFNOSUPPORT) {
+ return false;
+ }
+ LOG_ALWAYS_FATAL("Could not setup vsock server: %s", statusToString(status).c_str());
+ }
server->start();
- sp<RpcSession> session = RpcSession::make();
- bool okay = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
+ sp<RpcSession> session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+ status_t status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
while (!server->shutdown()) usleep(10000);
- ALOGE("Detected vsock loopback supported: %d", okay);
- return okay;
+ ALOGE("Detected vsock loopback supported: %s", statusToString(status).c_str());
+ return status == OK;
}
static std::vector<SocketType> testSocketTypes() {
- std::vector<SocketType> ret = {SocketType::UNIX, SocketType::INET};
+ std::vector<SocketType> ret = {SocketType::PRECONNECTED, SocketType::UNIX, SocketType::INET};
static bool hasVsockLoopback = testSupportVsockLoopback();
@@ -1155,10 +1223,13 @@
return ret;
}
-INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, ::testing::ValuesIn(testSocketTypes()),
- PrintSocketType);
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
+ ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
+ ::testing::ValuesIn(RpcSecurityValues())),
+ BinderRpc::PrintParamInfo);
-class BinderRpcServerRootObject : public ::testing::TestWithParam<std::tuple<bool, bool>> {};
+class BinderRpcServerRootObject
+ : public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {};
TEST_P(BinderRpcServerRootObject, WeakRootObject) {
using SetFn = std::function<void(RpcServer*, sp<IBinder>)>;
@@ -1166,8 +1237,8 @@
return isStrong ? SetFn(&RpcServer::setRootObject) : SetFn(&RpcServer::setRootObjectWeak);
};
- auto server = RpcServer::make();
- auto [isStrong1, isStrong2] = GetParam();
+ auto [isStrong1, isStrong2, rpcSecurity] = GetParam();
+ auto server = RpcServer::make(newFactory(rpcSecurity));
auto binder1 = sp<BBinder>::make();
IBinder* binderRaw1 = binder1.get();
setRootObject(isStrong1)(server.get(), binder1);
@@ -1184,7 +1255,8 @@
}
INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerRootObject,
- ::testing::Combine(::testing::Bool(), ::testing::Bool()));
+ ::testing::Combine(::testing::Bool(), ::testing::Bool(),
+ ::testing::ValuesIn(RpcSecurityValues())));
class OneOffSignal {
public:
@@ -1207,12 +1279,12 @@
bool mValue = false;
};
-TEST(BinderRpc, Shutdown) {
+TEST_P(BinderRpcSimple, Shutdown) {
auto addr = allocateSocketAddress();
unlink(addr.c_str());
- auto server = RpcServer::make();
+ auto server = RpcServer::make(newFactory(GetParam()));
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
- ASSERT_TRUE(server->setupUnixDomainServer(addr.c_str()));
+ ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
auto joinEnds = std::make_shared<OneOffSignal>();
// If things are broken and the thread never stops, don't block other tests. Because the thread
@@ -1253,14 +1325,14 @@
auto rpcServer = RpcServer::make();
rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
unsigned int port;
- ASSERT_TRUE(rpcServer->setupInetServer(0, &port));
+ ASSERT_EQ(OK, rpcServer->setupInetServer(kLocalInetAddress, 0, &port));
auto socket = rpcServer->releaseServer();
auto keepAlive = sp<BBinder>::make();
ASSERT_EQ(OK, binder->setRpcClientDebug(std::move(socket), keepAlive));
auto rpcSession = RpcSession::make();
- ASSERT_TRUE(rpcSession->setupInetClient("127.0.0.1", port));
+ ASSERT_EQ(OK, rpcSession->setupInetClient("127.0.0.1", port));
auto rpcBinder = rpcSession->getRootObject();
ASSERT_NE(nullptr, rpcBinder);
@@ -1271,6 +1343,9 @@
ASSERT_EQ(OK, rpcBinder->pingBinder());
}
+INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
+ BinderRpcSimple::PrintTestParam);
+
} // namespace android
int main(int argc, char** argv) {
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 74b8eb8..acf3f8f 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -23,7 +23,6 @@
"main.cpp",
"random_fd.cpp",
"random_parcel.cpp",
- "util.cpp",
],
static_libs: [
"libbase",
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 5f2c17c..9fe06dd 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -18,11 +18,13 @@
#include "binder.h"
#include "util.h"
+#include <android-base/hex.h>
#include <android/os/IServiceManager.h>
#include <binder/ParcelableHolder.h>
#include <binder/PersistableBundle.h>
using ::android::status_t;
+using ::android::base::HexString;
enum ByteEnum : int8_t {};
enum IntEnum : int32_t {};
@@ -128,7 +130,7 @@
[] (const ::android::Parcel& p, uint8_t len) {
FUZZ_LOG() << "about to readInplace";
const void* r = p.readInplace(len);
- FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << hexString(r, len);
+ FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << (r ? HexString(r, len) : "null");
},
PARCEL_READ_OPT_STATUS(int32_t, readInt32),
PARCEL_READ_OPT_STATUS(uint32_t, readUint32),
@@ -156,7 +158,7 @@
FUZZ_LOG() << "about to readString16Inplace";
size_t outLen = 0;
const char16_t* str = p.readString16Inplace(&outLen);
- FUZZ_LOG() << "readString16Inplace: " << hexString(str, sizeof(char16_t) * outLen)
+ FUZZ_LOG() << "readString16Inplace: " << HexString(str, sizeof(char16_t) * outLen)
<< " size: " << outLen;
},
PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readStrongBinder),
diff --git a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
index 35b5ebc..ee9840f 100644
--- a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
@@ -18,10 +18,12 @@
#include "hwbinder.h"
#include "util.h"
+#include <android-base/hex.h>
#include <android-base/logging.h>
#include <hwbinder/Parcel.h>
using ::android::status_t;
+using ::android::base::HexString;
// TODO: support scatter-gather types
@@ -70,13 +72,13 @@
FUZZ_LOG() << "about to read";
std::vector<uint8_t> data (length);
status_t status = p.read(data.data(), length);
- FUZZ_LOG() << "read status: " << status << " data: " << hexString(data.data(), data.size());
+ FUZZ_LOG() << "read status: " << status << " data: " << HexString(data.data(), data.size());
},
[] (const ::android::hardware::Parcel& p, uint8_t length) {
FUZZ_LOG() << "about to read";
std::vector<uint8_t> data (length);
const void* inplace = p.readInplace(length);
- FUZZ_LOG() << "read status: " << hexString(inplace, length);
+ FUZZ_LOG() << "read status: " << (inplace ? HexString(inplace, length) : "null");
},
PARCEL_READ_WITH_STATUS(int8_t, readInt8),
PARCEL_READ_WITH_STATUS(uint8_t, readUint8),
@@ -100,7 +102,7 @@
FUZZ_LOG() << "about to readString16Inplace";
size_t outSize = 0;
const char16_t* str = p.readString16Inplace(&outSize);
- FUZZ_LOG() << "readString16Inplace: " << hexString(str, sizeof(char16_t) * outSize);
+ FUZZ_LOG() << "readString16Inplace: " << HexString(str, sizeof(char16_t) * outSize);
},
PARCEL_READ_OPT_STATUS(::android::sp<::android::hardware::IBinder>, readStrongBinder),
PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readNullableStrongBinder),
diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp
index 2a79e85..f435dae 100644
--- a/libs/binder/tests/parcel_fuzzer/main.cpp
+++ b/libs/binder/tests/parcel_fuzzer/main.cpp
@@ -22,6 +22,7 @@
#include <iostream>
+#include <android-base/hex.h>
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
#include <android/binder_libbinder.h>
@@ -35,6 +36,7 @@
using android::fillRandomParcel;
using android::sp;
+using android::base::HexString;
void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
// TODO: functionality to create random parcels for libhwbinder parcels
@@ -78,8 +80,8 @@
CHECK(reads.size() <= 255) << reads.size();
FUZZ_LOG() << "backend: " << backend;
- FUZZ_LOG() << "input: " << hexString(p.data(), p.dataSize());
- FUZZ_LOG() << "instructions: " << hexString(instructions);
+ FUZZ_LOG() << "input: " << HexString(p.data(), p.dataSize());
+ FUZZ_LOG() << "instructions: " << HexString(instructions.data(), instructions.size());
for (size_t i = 0; i + 1 < instructions.size(); i += 2) {
uint8_t a = instructions[i];
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 92fdc72..8bf04cc 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <binder/IServiceManager.h>
#include <binder/RpcSession.h>
+#include <binder/RpcTransportRaw.h>
#include <fuzzbinder/random_fd.h>
#include <utils/String16.h>
@@ -35,8 +36,8 @@
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
if (provider.ConsumeBool()) {
- auto session = sp<RpcSession>::make();
- CHECK(session->addNullDebuggingClient());
+ auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+ CHECK_EQ(OK, session->addNullDebuggingClient());
p->markForRpc(session);
fillRandomParcelData(p, std::move(provider));
return;
diff --git a/libs/binder/tests/parcel_fuzzer/util.cpp b/libs/binder/tests/parcel_fuzzer/util.cpp
deleted file mode 100644
index 479f406..0000000
--- a/libs/binder/tests/parcel_fuzzer/util.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-#define FUZZ_LOG_TAG "util"
-#include "util.h"
-
-#include <android-base/logging.h>
-
-#include <iomanip>
-#include <sstream>
-
-std::string hexString(const void* bytes, size_t len) {
- if (bytes == nullptr) return "<null>";
-
- const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
- char chars[] = "0123456789abcdef";
- std::string result;
- result.resize(len * 2);
-
- for (size_t i = 0; i < len; i++) {
- result[2 * i] = chars[bytes8[i] >> 4];
- result[2 * i + 1] = chars[bytes8[i] & 0xf];
- }
-
- return result;
-}
-std::string hexString(const std::vector<uint8_t>& bytes) {
- return hexString(bytes.data(), bytes.size());
-}
diff --git a/libs/binder/tests/parcel_fuzzer/util.h b/libs/binder/tests/parcel_fuzzer/util.h
index 45e8c57..a5d0dae 100644
--- a/libs/binder/tests/parcel_fuzzer/util.h
+++ b/libs/binder/tests/parcel_fuzzer/util.h
@@ -49,6 +49,3 @@
FuzzLog& log() { return *this; }
};
#endif
-
-std::string hexString(const void* bytes, size_t len);
-std::string hexString(const std::vector<uint8_t>& bytes);
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index 9fc496f..230f5c7 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -60,7 +60,7 @@
sp<RpcServer> server = RpcServer::make();
server->setRootObject(sp<SomeBinder>::make());
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
- CHECK(server->setupUnixDomainServer(kSock.c_str()));
+ CHECK_EQ(OK, server->setupUnixDomainServer(kSock.c_str()));
std::thread serverThread([=] { (void)server->join(); });