Merge "Set min_sdk_version"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 9bd733d..b94f3da 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -1194,6 +1194,11 @@
bool traceStream = false;
bool onlyUserspace = false;
+ fprintf(stderr,
+ "** Warning: atrace will end vendor support in the next Android Release. **\n"
+ "** Perfetto is the suggested replacement tool. It will gain vendor **\n"
+ "** support. See https://perfetto.dev/docs/quickstart/android-tracing **\n\n");
+
if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
showHelp(argv[0]);
exit(0);
diff --git a/include/input/OWNERS b/include/input/OWNERS
new file mode 100644
index 0000000..c88bfe9
--- /dev/null
+++ b/include/input/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/INPUT_OWNERS
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 9389bec..27000e8 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -174,6 +174,7 @@
"-Wreorder-init-list",
"-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
"-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
+ "-DBINDER_WITH_KERNEL_IPC",
],
product_variables: {
binder32bit: {
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index e2db1a3..b9a8ba9 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -38,6 +38,7 @@
#include <linux/sched.h>
#endif
+#include "BuildFlags.h"
#include "RpcState.h"
namespace android {
@@ -164,6 +165,10 @@
ALOGW("setRpcClientDebug disallowed because RPC is not enabled");
return INVALID_OPERATION;
}
+ if (!kEnableKernelIpc) {
+ ALOGW("setRpcClientDebug disallowed because kernel binder is not enabled");
+ return INVALID_OPERATION;
+ }
BBinder* local = this->localBinder();
if (local != nullptr) {
@@ -515,6 +520,10 @@
ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__);
return INVALID_OPERATION;
}
+ if (!kEnableKernelIpc) {
+ ALOGW("setRpcClientDebug disallowed because kernel binder is not enabled");
+ return INVALID_OPERATION;
+ }
uid_t uid = IPCThreadState::self()->getCallingUid();
if (uid != AID_ROOT) {
ALOGE("%s: not allowed because client %" PRIu32 " is not root", __PRETTY_FUNCTION__, uid);
@@ -540,6 +549,10 @@
ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__);
return INVALID_OPERATION;
}
+ if (!kEnableKernelIpc) {
+ ALOGW("setRpcClientDebug disallowed because kernel binder is not enabled");
+ return INVALID_OPERATION;
+ }
const int socketFdForPrint = socketFd.get();
LOG_RPC_DETAIL("%s(fd=%d)", __PRETTY_FUNCTION__, socketFdForPrint);
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 1eb2ffd..49fc195 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -28,6 +28,8 @@
#include <stdio.h>
+#include "BuildFlags.h"
+
//#undef ALOGV
//#define ALOGV(...) fprintf(stderr, __VA_ARGS__)
@@ -115,6 +117,11 @@
// ---------------------------------------------------------------------------
sp<BpBinder> BpBinder::create(int32_t handle) {
+ if constexpr (!kEnableKernelIpc) {
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return nullptr;
+ }
+
int32_t trackedUid = -1;
if (sCountByUidEnabled) {
trackedUid = IPCThreadState::self()->getCallingUid();
@@ -177,6 +184,11 @@
}
BpBinder::BpBinder(BinderHandle&& handle, int32_t trackedUid) : BpBinder(Handle(handle)) {
+ if constexpr (!kEnableKernelIpc) {
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return;
+ }
+
mTrackedUid = trackedUid;
ALOGV("Creating BpBinder %p handle %d\n", this, this->binderHandle());
@@ -303,6 +315,11 @@
status = rpcSession()->transact(sp<IBinder>::fromExisting(this), code, data, reply,
flags);
} else {
+ if constexpr (!kEnableKernelIpc) {
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return INVALID_OPERATION;
+ }
+
status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
}
if (data.dataSize() > LOG_TRANSACTIONS_OVER_SIZE) {
@@ -328,6 +345,11 @@
{
if (isRpcBinder()) return UNKNOWN_TRANSACTION;
+ if constexpr (!kEnableKernelIpc) {
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return INVALID_OPERATION;
+ }
+
Obituary ob;
ob.recipient = recipient;
ob.cookie = cookie;
@@ -366,6 +388,11 @@
{
if (isRpcBinder()) return UNKNOWN_TRANSACTION;
+ if constexpr (!kEnableKernelIpc) {
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return INVALID_OPERATION;
+ }
+
AutoMutex _l(mLock);
if (mObitsSent) {
@@ -401,6 +428,11 @@
{
LOG_ALWAYS_FATAL_IF(isRpcBinder(), "Cannot send obituary for remote binder.");
+ if constexpr (!kEnableKernelIpc) {
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return;
+ }
+
ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n", this, binderHandle(),
mObitsSent ? "true" : "false");
@@ -469,12 +501,16 @@
return this;
}
-BpBinder::~BpBinder()
-{
- ALOGV("Destroying BpBinder %p handle %d\n", this, binderHandle());
-
+BpBinder::~BpBinder() {
if (CC_UNLIKELY(isRpcBinder())) return;
+ if constexpr (!kEnableKernelIpc) {
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return;
+ }
+
+ ALOGV("Destroying BpBinder %p handle %d\n", this, binderHandle());
+
IPCThreadState* ipc = IPCThreadState::self();
if (mTrackedUid >= 0) {
@@ -505,21 +541,31 @@
}
}
-void BpBinder::onFirstRef()
-{
- ALOGV("onFirstRef BpBinder %p handle %d\n", this, binderHandle());
+void BpBinder::onFirstRef() {
if (CC_UNLIKELY(isRpcBinder())) return;
+
+ if constexpr (!kEnableKernelIpc) {
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return;
+ }
+
+ ALOGV("onFirstRef BpBinder %p handle %d\n", this, binderHandle());
IPCThreadState* ipc = IPCThreadState::self();
if (ipc) ipc->incStrongHandle(binderHandle(), this);
}
-void BpBinder::onLastStrongRef(const void* /*id*/)
-{
- ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, binderHandle());
+void BpBinder::onLastStrongRef(const void* /*id*/) {
if (CC_UNLIKELY(isRpcBinder())) {
(void)rpcSession()->sendDecStrong(this);
return;
}
+
+ if constexpr (!kEnableKernelIpc) {
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return;
+ }
+
+ ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, binderHandle());
IF_ALOGV() {
printRefs();
}
@@ -552,6 +598,11 @@
// RPC binder doesn't currently support inc from weak binders
if (CC_UNLIKELY(isRpcBinder())) return false;
+ if constexpr (!kEnableKernelIpc) {
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return false;
+ }
+
ALOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, binderHandle());
IPCThreadState* ipc = IPCThreadState::self();
return ipc ? ipc->attemptIncStrongHandle(binderHandle()) == NO_ERROR : false;
diff --git a/libs/binder/BuildFlags.h b/libs/binder/BuildFlags.h
new file mode 100644
index 0000000..3e9d1c2
--- /dev/null
+++ b/libs/binder/BuildFlags.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace android {
+
+#ifdef BINDER_RPC_SINGLE_THREADED
+constexpr bool kEnableRpcThreads = false;
+#else
+constexpr bool kEnableRpcThreads = true;
+#endif
+
+#ifdef BINDER_WITH_KERNEL_IPC
+constexpr bool kEnableKernelIpc = true;
+#else // BINDER_WITH_KERNEL_IPC
+constexpr bool kEnableKernelIpc = false;
+#endif // BINDER_WITH_KERNEL_IPC
+
+} // namespace android
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index e4ac4b4..c6e4fb3 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -15,6 +15,7 @@
*/
#include "Debug.h"
+#include "BuildFlags.h"
#include <binder/ProcessState.h>
@@ -301,6 +302,11 @@
}
ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf) {
+ if constexpr (!kEnableKernelIpc) {
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return 0;
+ }
+
sp<ProcessState> proc = ProcessState::selfOrNull();
if (proc.get() == nullptr) {
return 0;
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
index 5e22593..d123fd1 100644
--- a/libs/binder/FdTrigger.cpp
+++ b/libs/binder/FdTrigger.cpp
@@ -28,25 +28,45 @@
std::unique_ptr<FdTrigger> FdTrigger::make() {
auto ret = std::make_unique<FdTrigger>();
+#ifndef BINDER_RPC_SINGLE_THREADED
if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) {
ALOGE("Could not create pipe %s", strerror(errno));
return nullptr;
}
+#endif
return ret;
}
void FdTrigger::trigger() {
+#ifdef BINDER_RPC_SINGLE_THREADED
+ mTriggered = true;
+#else
mWrite.reset();
+#endif
}
bool FdTrigger::isTriggered() {
+#ifdef BINDER_RPC_SINGLE_THREADED
+ return mTriggered;
+#else
return mWrite == -1;
+#endif
}
status_t FdTrigger::triggerablePoll(base::borrowed_fd fd, int16_t event) {
+#ifdef BINDER_RPC_SINGLE_THREADED
+ if (mTriggered) {
+ return DEAD_OBJECT;
+ }
+#endif
+
LOG_ALWAYS_FATAL_IF(event == 0, "triggerablePoll %d with event 0 is not allowed", fd.get());
- pollfd pfd[]{{.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
- {.fd = mRead.get(), .events = 0, .revents = 0}};
+ pollfd pfd[]{
+ {.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
+#ifndef BINDER_RPC_SINGLE_THREADED
+ {.fd = mRead.get(), .events = 0, .revents = 0},
+#endif
+ };
int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
if (ret < 0) {
return -errno;
@@ -55,6 +75,7 @@
// At least one FD has events. Check them.
+#ifndef BINDER_RPC_SINGLE_THREADED
// Detect explicit trigger(): DEAD_OBJECT
if (pfd[1].revents & POLLHUP) {
return DEAD_OBJECT;
@@ -68,6 +89,7 @@
// pfd[1].revents is 0, hence pfd[0].revents must be set, and only possible values are
// a subset of event | POLLHUP | POLLERR | POLLNVAL.
+#endif
// POLLNVAL: invalid FD number, e.g. not opened.
if (pfd[0].revents & POLLNVAL) {
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
index a545d6c..5c7102e 100644
--- a/libs/binder/FdTrigger.h
+++ b/libs/binder/FdTrigger.h
@@ -55,7 +55,11 @@
[[nodiscard]] status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
private:
+#ifdef BINDER_RPC_SINGLE_THREADED
+ bool mTriggered = false;
+#else
base::unique_fd mWrite;
base::unique_fd mRead;
+#endif
};
} // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index e67dd7b..3dccf20 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -20,15 +20,14 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <linux/sched.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
+#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/resource.h>
#include <unistd.h>
#include <binder/Binder.h>
@@ -40,6 +39,7 @@
#include <binder/Status.h>
#include <binder/TextOutput.h>
+#include <android-base/scopeguard.h>
#include <cutils/ashmem.h>
#include <cutils/compiler.h>
#include <utils/Flattenable.h>
@@ -51,12 +51,27 @@
#include "RpcState.h"
#include "Static.h"
#include "Utils.h"
+
+// A lot of code in this file uses definitions from the
+// Linux kernel header for Binder <linux/android/binder.h>
+// which is included indirectly via "binder_module.h".
+// Non-Linux OSes do not have that header, so libbinder should be
+// built for those targets without kernel binder support, i.e.,
+// without BINDER_WITH_KERNEL_IPC. For this reason, all code in this
+// file that depends on kernel binder, including the header itself,
+// is conditional on BINDER_WITH_KERNEL_IPC.
+#ifdef BINDER_WITH_KERNEL_IPC
+#include <linux/sched.h>
#include "binder_module.h"
+#else // BINDER_WITH_KERNEL_IPC
+// Needed by {read,write}Pointer
+typedef uintptr_t binder_uintptr_t;
+#endif // BINDER_WITH_KERNEL_IPC
#define LOG_REFS(...)
-//#define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+// #define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOG_ALLOC(...)
-//#define LOG_ALLOC(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+// #define LOG_ALLOC(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
// ---------------------------------------------------------------------------
@@ -99,6 +114,7 @@
BLOB_ASHMEM_MUTABLE = 2,
};
+#ifdef BINDER_WITH_KERNEL_IPC
static void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj,
const void* who) {
switch (obj.hdr.type) {
@@ -151,6 +167,11 @@
ALOGE("Invalid object type 0x%08x", obj.hdr.type);
}
+#endif // BINDER_WITH_KERNEL_IPC
+
+static int toRawFd(const std::variant<base::unique_fd, base::borrowed_fd>& v) {
+ return std::visit([](const auto& fd) { return fd.get(); }, v);
+}
Parcel::RpcFields::RpcFields(const sp<RpcSession>& session) : mSession(session) {
LOG_ALWAYS_FATAL_IF(mSession == nullptr);
@@ -178,9 +199,11 @@
return OK;
}
+#ifdef BINDER_WITH_KERNEL_IPC
static constexpr inline int schedPolicyMask(int policy, int priority) {
return (priority & FLAT_BINDER_FLAG_PRIORITY_MASK) | ((policy & 3) << FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT);
}
+#endif // BINDER_WITH_KERNEL_IPC
status_t Parcel::flattenBinder(const sp<IBinder>& binder) {
BBinder* local = nullptr;
@@ -205,6 +228,7 @@
return finishFlattenBinder(binder);
}
+#ifdef BINDER_WITH_KERNEL_IPC
flat_binder_object obj;
int schedBits = 0;
@@ -261,6 +285,10 @@
if (status != OK) return status;
return finishFlattenBinder(binder);
+#else // BINDER_WITH_KERNEL_IPC
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
}
status_t Parcel::unflattenBinder(sp<IBinder>* out) const
@@ -290,6 +318,7 @@
return finishUnflattenBinder(binder, out);
}
+#ifdef BINDER_WITH_KERNEL_IPC
const flat_binder_object* flat = readObject(false);
if (flat) {
@@ -307,6 +336,10 @@
}
}
return BAD_TYPE;
+#else // BINDER_WITH_KERNEL_IPC
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
}
// ---------------------------------------------------------------------------
@@ -470,6 +503,7 @@
err = NO_ERROR;
+#ifdef BINDER_WITH_KERNEL_IPC
if (auto* kernelFields = maybeKernelFields()) {
auto* otherKernelFields = parcel->maybeKernelFields();
LOG_ALWAYS_FATAL_IF(otherKernelFields == nullptr);
@@ -530,7 +564,65 @@
}
}
}
+ } else {
+ auto* rpcFields = maybeRpcFields();
+ LOG_ALWAYS_FATAL_IF(rpcFields == nullptr);
+ auto* otherRpcFields = parcel->maybeRpcFields();
+ if (otherRpcFields == nullptr) {
+ return BAD_TYPE;
+ }
+ if (rpcFields->mSession != otherRpcFields->mSession) {
+ return BAD_TYPE;
+ }
+
+ const size_t savedDataPos = mDataPos;
+ base::ScopeGuard scopeGuard = [&]() { mDataPos = savedDataPos; };
+
+ rpcFields->mObjectPositions.reserve(otherRpcFields->mObjectPositions.size());
+ if (otherRpcFields->mFds != nullptr) {
+ if (rpcFields->mFds == nullptr) {
+ rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
+ }
+ rpcFields->mFds->reserve(otherRpcFields->mFds->size());
+ }
+ for (size_t i = 0; i < otherRpcFields->mObjectPositions.size(); i++) {
+ const binder_size_t objPos = otherRpcFields->mObjectPositions[i];
+ if (offset <= objPos && objPos < offset + len) {
+ size_t newDataPos = objPos - offset + startPos;
+ rpcFields->mObjectPositions.push_back(newDataPos);
+
+ mDataPos = newDataPos;
+ int32_t objectType;
+ if (status_t status = readInt32(&objectType); status != OK) {
+ return status;
+ }
+ if (objectType != RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+ continue;
+ }
+
+ if (!mAllowFds) {
+ return FDS_NOT_ALLOWED;
+ }
+
+ // Read FD, duplicate, and add to list.
+ int32_t fdIndex;
+ if (status_t status = readInt32(&fdIndex); status != OK) {
+ return status;
+ }
+ const auto& oldFd = otherRpcFields->mFds->at(fdIndex);
+ // To match kernel binder behavior, we always dup, even if the
+ // FD was unowned in the source parcel.
+ rpcFields->mFds->emplace_back(
+ base::unique_fd(fcntl(toRawFd(oldFd), F_DUPFD_CLOEXEC, 0)));
+ // Fixup the index in the data.
+ mDataPos = newDataPos + 4;
+ if (status_t status = writeInt32(rpcFields->mFds->size() - 1); status != OK) {
+ return status;
+ }
+ }
+ }
}
+#endif // BINDER_WITH_KERNEL_IPC
return err;
}
@@ -584,7 +676,7 @@
bool Parcel::hasFileDescriptors() const
{
if (const auto* rpcFields = maybeRpcFields()) {
- return false;
+ return rpcFields->mFds != nullptr && !rpcFields->mFds->empty();
}
auto* kernelFields = maybeKernelFields();
if (!kernelFields->mFdsKnown) {
@@ -596,6 +688,7 @@
std::vector<sp<IBinder>> Parcel::debugReadAllStrongBinders() const {
std::vector<sp<IBinder>> ret;
+#ifdef BINDER_WITH_KERNEL_IPC
const auto* kernelFields = maybeKernelFields();
if (kernelFields == nullptr) {
return ret;
@@ -615,40 +708,43 @@
}
setDataPosition(initPosition);
+#endif // BINDER_WITH_KERNEL_IPC
+
return ret;
}
std::vector<int> Parcel::debugReadAllFileDescriptors() const {
std::vector<int> ret;
- const auto* kernelFields = maybeKernelFields();
- if (kernelFields == nullptr) {
- return ret;
+ if (const auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
+ size_t initPosition = dataPosition();
+ for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
+ binder_size_t offset = kernelFields->mObjects[i];
+ const flat_binder_object* flat =
+ reinterpret_cast<const flat_binder_object*>(mData + offset);
+ if (flat->hdr.type != BINDER_TYPE_FD) continue;
+
+ setDataPosition(offset);
+
+ int fd = readFileDescriptor();
+ LOG_ALWAYS_FATAL_IF(fd == -1);
+ ret.push_back(fd);
+ }
+ setDataPosition(initPosition);
+#else
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+#endif
+ } else if (const auto* rpcFields = maybeRpcFields(); rpcFields && rpcFields->mFds) {
+ for (const auto& fd : *rpcFields->mFds) {
+ ret.push_back(toRawFd(fd));
+ }
}
- size_t initPosition = dataPosition();
- for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
- binder_size_t offset = kernelFields->mObjects[i];
- const flat_binder_object* flat =
- reinterpret_cast<const flat_binder_object*>(mData + offset);
- if (flat->hdr.type != BINDER_TYPE_FD) continue;
-
- setDataPosition(offset);
-
- int fd = readFileDescriptor();
- LOG_ALWAYS_FATAL_IF(fd == -1);
- ret.push_back(fd);
- }
-
- setDataPosition(initPosition);
return ret;
}
status_t Parcel::hasFileDescriptorsInRange(size_t offset, size_t len, bool* result) const {
- const auto* kernelFields = maybeKernelFields();
- if (kernelFields == nullptr) {
- return BAD_TYPE;
- }
if (len > INT32_MAX || offset > INT32_MAX) {
// Don't accept size_t values which may have come from an inadvertent conversion from a
// negative int.
@@ -659,20 +755,38 @@
return BAD_VALUE;
}
*result = false;
- for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
- size_t pos = kernelFields->mObjects[i];
- if (pos < offset) continue;
- if (pos + sizeof(flat_binder_object) > offset + len) {
- if (kernelFields->mObjectsSorted) {
+ if (const auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
+ for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
+ size_t pos = kernelFields->mObjects[i];
+ if (pos < offset) continue;
+ if (pos + sizeof(flat_binder_object) > offset + len) {
+ if (kernelFields->mObjectsSorted) {
+ break;
+ } else {
+ continue;
+ }
+ }
+ const flat_binder_object* flat =
+ reinterpret_cast<const flat_binder_object*>(mData + pos);
+ if (flat->hdr.type == BINDER_TYPE_FD) {
+ *result = true;
break;
- } else {
- continue;
}
}
- const flat_binder_object* flat = reinterpret_cast<const flat_binder_object*>(mData + pos);
- if (flat->hdr.type == BINDER_TYPE_FD) {
- *result = true;
- break;
+#else
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
+ } else if (const auto* rpcFields = maybeRpcFields()) {
+ for (uint32_t pos : rpcFields->mObjectPositions) {
+ if (offset <= pos && pos < limit) {
+ const auto* type = reinterpret_cast<const RpcFields::ObjectType*>(mData + pos);
+ if (*type == RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+ *result = true;
+ break;
+ }
+ }
}
}
return NO_ERROR;
@@ -716,6 +830,7 @@
}
}
+#ifdef BINDER_WITH_KERNEL_IPC
#if defined(__ANDROID_VNDK__)
constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
#elif defined(__ANDROID_RECOVERY__)
@@ -723,6 +838,7 @@
#else
constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
#endif
+#endif // BINDER_WITH_KERNEL_IPC
// Write RPC headers. (previously just the interface token)
status_t Parcel::writeInterfaceToken(const String16& interface)
@@ -732,12 +848,17 @@
status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) {
if (auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
const IPCThreadState* threadState = IPCThreadState::self();
writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
updateWorkSourceRequestHeaderPosition();
writeInt32(threadState->shouldPropagateWorkSource() ? threadState->getCallingWorkSourceUid()
: IPCThreadState::kUnsetWorkSource);
writeInt32(kHeader);
+#else // BINDER_WITH_KERNEL_IPC
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
}
// currently the interface identification token is just its name as a string
@@ -794,6 +915,7 @@
IPCThreadState* threadState) const
{
if (auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
// StrictModePolicy.
int32_t strictPolicy = readInt32();
if (threadState == nullptr) {
@@ -819,6 +941,11 @@
header);
return false;
}
+#else // BINDER_WITH_KERNEL_IPC
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ (void)threadState;
+ return false;
+#endif // BINDER_WITH_KERNEL_IPC
}
// Interface descriptor.
@@ -1293,13 +1420,43 @@
return err;
}
-status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership)
-{
- if (isForRpc()) {
- ALOGE("Cannot write file descriptor to remote binder.");
- return BAD_TYPE;
+status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) {
+ if (auto* rpcFields = maybeRpcFields()) {
+ std::variant<base::unique_fd, base::borrowed_fd> fdVariant;
+ if (takeOwnership) {
+ fdVariant = base::unique_fd(fd);
+ } else {
+ fdVariant = base::borrowed_fd(fd);
+ }
+ if (!mAllowFds) {
+ return FDS_NOT_ALLOWED;
+ }
+ switch (rpcFields->mSession->getFileDescriptorTransportMode()) {
+ case RpcSession::FileDescriptorTransportMode::NONE: {
+ return FDS_NOT_ALLOWED;
+ }
+ case RpcSession::FileDescriptorTransportMode::UNIX: {
+ if (rpcFields->mFds == nullptr) {
+ rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
+ }
+ size_t dataPos = mDataPos;
+ if (dataPos > UINT32_MAX) {
+ return NO_MEMORY;
+ }
+ if (status_t err = writeInt32(RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR); err != OK) {
+ return err;
+ }
+ if (status_t err = writeInt32(rpcFields->mFds->size()); err != OK) {
+ return err;
+ }
+ rpcFields->mObjectPositions.push_back(dataPos);
+ rpcFields->mFds->push_back(std::move(fdVariant));
+ return OK;
+ }
+ }
}
+#ifdef BINDER_WITH_KERNEL_IPC
flat_binder_object obj;
obj.hdr.type = BINDER_TYPE_FD;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
@@ -1307,6 +1464,12 @@
obj.handle = fd;
obj.cookie = takeOwnership ? 1 : 0;
return writeObject(obj, true);
+#else // BINDER_WITH_KERNEL_IPC
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ (void)fd;
+ (void)takeOwnership;
+ return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
}
status_t Parcel::writeDupFileDescriptor(int fd)
@@ -1460,6 +1623,7 @@
auto* kernelFields = maybeKernelFields();
LOG_ALWAYS_FATAL_IF(kernelFields == nullptr, "Can't write flat_binder_object to RPC Parcel");
+#ifdef BINDER_WITH_KERNEL_IPC
const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
const bool enoughObjects = kernelFields->mObjectsSize < kernelFields->mObjectsCapacity;
if (enoughData && enoughObjects) {
@@ -1502,6 +1666,12 @@
}
goto restart_write;
+#else // BINDER_WITH_KERNEL_IPC
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ (void)val;
+ (void)nullMetaData;
+ return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
}
status_t Parcel::writeNoException()
@@ -1519,6 +1689,7 @@
return OK;
}
+#ifdef BINDER_WITH_KERNEL_IPC
// Don't allow non-object reads on object data
if (kernelFields->mObjectsSorted || kernelFields->mObjectsSize <= 1) {
data_sorted:
@@ -1571,6 +1742,10 @@
kernelFields->mNextObjectHint = 0;
kernelFields->mObjectsSorted = true;
goto data_sorted;
+#else // BINDER_WITH_KERNEL_IPC
+ (void)upperBound;
+ return NO_ERROR;
+#endif // BINDER_WITH_KERNEL_IPC
}
status_t Parcel::read(void* outData, size_t len) const
@@ -2038,8 +2213,32 @@
return h;
}
-int Parcel::readFileDescriptor() const
-{
+int Parcel::readFileDescriptor() const {
+ if (const auto* rpcFields = maybeRpcFields()) {
+ if (!std::binary_search(rpcFields->mObjectPositions.begin(),
+ rpcFields->mObjectPositions.end(), mDataPos)) {
+ ALOGW("Attempt to read file descriptor from Parcel %p at offset %zu that is not in the "
+ "object list",
+ this, mDataPos);
+ return BAD_TYPE;
+ }
+
+ int32_t objectType = readInt32();
+ if (objectType != RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+ return BAD_TYPE;
+ }
+
+ int32_t fdIndex = readInt32();
+ if (rpcFields->mFds == nullptr || fdIndex < 0 ||
+ static_cast<size_t>(fdIndex) >= rpcFields->mFds->size()) {
+ ALOGE("RPC Parcel contains invalid file descriptor index. index=%d fd_count=%zu",
+ fdIndex, rpcFields->mFds ? rpcFields->mFds->size() : 0);
+ return BAD_VALUE;
+ }
+ return toRawFd(rpcFields->mFds->at(fdIndex));
+ }
+
+#ifdef BINDER_WITH_KERNEL_IPC
const flat_binder_object* flat = readObject(true);
if (flat && flat->hdr.type == BINDER_TYPE_FD) {
@@ -2047,10 +2246,13 @@
}
return BAD_TYPE;
+#else // BINDER_WITH_KERNEL_IPC
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
}
-int Parcel::readParcelFileDescriptor() const
-{
+int Parcel::readParcelFileDescriptor() const {
int32_t hasComm = readInt32();
int fd = readFileDescriptor();
if (hasComm != 0) {
@@ -2203,6 +2405,8 @@
return err;
}
+
+#ifdef BINDER_WITH_KERNEL_IPC
const flat_binder_object* Parcel::readObject(bool nullMetaData) const
{
const auto* kernelFields = maybeKernelFields();
@@ -2268,24 +2472,29 @@
}
return nullptr;
}
+#endif // BINDER_WITH_KERNEL_IPC
void Parcel::closeFileDescriptors() {
- auto* kernelFields = maybeKernelFields();
- if (kernelFields == nullptr) {
- return;
- }
- size_t i = kernelFields->mObjectsSize;
- if (i > 0) {
- //ALOGI("Closing file descriptors for %zu objects...", i);
- }
- while (i > 0) {
- i--;
- const flat_binder_object* flat =
- reinterpret_cast<flat_binder_object*>(mData + kernelFields->mObjects[i]);
- if (flat->hdr.type == BINDER_TYPE_FD) {
- //ALOGI("Closing fd: %ld", flat->handle);
- close(flat->handle);
+ if (auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
+ size_t i = kernelFields->mObjectsSize;
+ if (i > 0) {
+ // ALOGI("Closing file descriptors for %zu objects...", i);
}
+ while (i > 0) {
+ i--;
+ const flat_binder_object* flat =
+ reinterpret_cast<flat_binder_object*>(mData + kernelFields->mObjects[i]);
+ if (flat->hdr.type == BINDER_TYPE_FD) {
+ // ALOGI("Closing fd: %ld", flat->handle);
+ close(flat->handle);
+ }
+ }
+#else // BINDER_WITH_KERNEL_IPC
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+#endif // BINDER_WITH_KERNEL_IPC
+ } else if (auto* rpcFields = maybeRpcFields()) {
+ rpcFields->mFds.reset();
}
}
@@ -2331,6 +2540,7 @@
kernelFields->mObjectsSize = kernelFields->mObjectsCapacity = objectsCount;
mOwner = relFunc;
+#ifdef BINDER_WITH_KERNEL_IPC
binder_size_t minOffset = 0;
for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
binder_size_t offset = kernelFields->mObjects[i];
@@ -2361,10 +2571,17 @@
minOffset = offset + sizeof(flat_binder_object);
}
scanForFds();
+#else // BINDER_WITH_KERNEL_IPC
+ LOG_ALWAYS_FATAL_IF(objectsCount != 0,
+ "Non-zero objects count passed to Parcel with kernel driver disabled");
+#endif // BINDER_WITH_KERNEL_IPC
}
-void Parcel::rpcSetDataReference(const sp<RpcSession>& session, const uint8_t* data,
- size_t dataSize, release_func relFunc) {
+status_t Parcel::rpcSetDataReference(
+ const sp<RpcSession>& session, const uint8_t* data, size_t dataSize,
+ const uint32_t* objectTable, size_t objectTableSize,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds,
+ release_func relFunc) {
// this code uses 'mOwner == nullptr' to understand whether it owns memory
LOG_ALWAYS_FATAL_IF(relFunc == nullptr, "must provide cleanup function");
@@ -2373,9 +2590,29 @@
freeData();
markForRpc(session);
+ auto* rpcFields = maybeRpcFields();
+ LOG_ALWAYS_FATAL_IF(rpcFields == nullptr); // guaranteed by markForRpc.
+
mData = const_cast<uint8_t*>(data);
mDataSize = mDataCapacity = dataSize;
mOwner = relFunc;
+
+ if (objectTableSize != ancillaryFds.size()) {
+ ALOGE("objectTableSize=%zu ancillaryFds.size=%zu", objectTableSize, ancillaryFds.size());
+ freeData(); // don't leak mData
+ return BAD_VALUE;
+ }
+
+ rpcFields->mObjectPositions.reserve(objectTableSize);
+ for (size_t i = 0; i < objectTableSize; i++) {
+ rpcFields->mObjectPositions.push_back(objectTable[i]);
+ }
+ if (!ancillaryFds.empty()) {
+ rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
+ *rpcFields->mFds = std::move(ancillaryFds);
+ }
+
+ return OK;
}
void Parcel::print(TextOutput& to, uint32_t /*flags*/) const
@@ -2388,6 +2625,7 @@
} else if (dataSize() > 0) {
const uint8_t* DATA = data();
to << indent << HexDump(DATA, dataSize()) << dedent;
+#ifdef BINDER_WITH_KERNEL_IPC
if (const auto* kernelFields = maybeKernelFields()) {
const binder_size_t* OBJS = kernelFields->mObjects;
const size_t N = objectsCount();
@@ -2399,6 +2637,7 @@
<< TypeCode(flat->hdr.type & 0x7f7f7f00) << " = " << flat->binder;
}
}
+#endif // BINDER_WITH_KERNEL_IPC
} else {
to << "NULL";
}
@@ -2413,6 +2652,7 @@
return;
}
+#ifdef BINDER_WITH_KERNEL_IPC
size_t i = kernelFields->mObjectsSize;
if (i == 0) {
return;
@@ -2425,6 +2665,7 @@
const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(data + objects[i]);
release_object(proc, *flat, this);
}
+#endif // BINDER_WITH_KERNEL_IPC
}
void Parcel::acquireObjects()
@@ -2434,6 +2675,7 @@
return;
}
+#ifdef BINDER_WITH_KERNEL_IPC
size_t i = kernelFields->mObjectsSize;
if (i == 0) {
return;
@@ -2446,6 +2688,7 @@
const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(data + objects[i]);
acquire_object(proc, *flat, this);
}
+#endif // BINDER_WITH_KERNEL_IPC
}
void Parcel::freeData()
@@ -2558,6 +2801,9 @@
kernelFields->mObjectsSorted = false;
kernelFields->mHasFds = false;
kernelFields->mFdsKnown = true;
+ } else if (auto* rpcFields = maybeRpcFields()) {
+ rpcFields->mObjectPositions.clear();
+ rpcFields->mFds.reset();
}
mAllowFds = true;
@@ -2573,17 +2819,26 @@
}
auto* kernelFields = maybeKernelFields();
+ auto* rpcFields = maybeRpcFields();
// If shrinking, first adjust for any objects that appear
// after the new data size.
- size_t objectsSize = kernelFields ? kernelFields->mObjectsSize : 0;
- if (kernelFields && desired < mDataSize) {
+ size_t objectsSize =
+ kernelFields ? kernelFields->mObjectsSize : rpcFields->mObjectPositions.size();
+ if (desired < mDataSize) {
if (desired == 0) {
objectsSize = 0;
} else {
- while (objectsSize > 0) {
- if (kernelFields->mObjects[objectsSize - 1] < desired) break;
- objectsSize--;
+ if (kernelFields) {
+ while (objectsSize > 0) {
+ if (kernelFields->mObjects[objectsSize - 1] < desired) break;
+ objectsSize--;
+ }
+ } else {
+ while (objectsSize > 0) {
+ if (rpcFields->mObjectPositions[objectsSize - 1] < desired) break;
+ objectsSize--;
+ }
}
}
}
@@ -2604,7 +2859,7 @@
}
binder_size_t* objects = nullptr;
- if (objectsSize) {
+ if (kernelFields && objectsSize) {
objects = (binder_size_t*)calloc(objectsSize, sizeof(binder_size_t));
if (!objects) {
free(data);
@@ -2620,6 +2875,12 @@
acquireObjects();
kernelFields->mObjectsSize = oldObjectsSize;
}
+ if (rpcFields) {
+ if (status_t status = truncateRpcObjects(objectsSize); status != OK) {
+ free(data);
+ return status;
+ }
+ }
if (mData) {
memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
@@ -2649,6 +2910,7 @@
} else if (mData) {
if (kernelFields && objectsSize < kernelFields->mObjectsSize) {
+#ifdef BINDER_WITH_KERNEL_IPC
// Need to release refs on any objects we are dropping.
const sp<ProcessState> proc(ProcessState::self());
for (size_t i = objectsSize; i < kernelFields->mObjectsSize; i++) {
@@ -2677,6 +2939,14 @@
kernelFields->mObjectsSize = objectsSize;
kernelFields->mNextObjectHint = 0;
kernelFields->mObjectsSorted = false;
+#else // BINDER_WITH_KERNEL_IPC
+ LOG_ALWAYS_FATAL("Non-zero numObjects for RPC Parcel");
+#endif // BINDER_WITH_KERNEL_IPC
+ }
+ if (rpcFields) {
+ if (status_t status = truncateRpcObjects(objectsSize); status != OK) {
+ return status;
+ }
}
// We own the data, so we can just do a realloc().
@@ -2734,6 +3004,35 @@
return NO_ERROR;
}
+status_t Parcel::truncateRpcObjects(size_t newObjectsSize) {
+ auto* rpcFields = maybeRpcFields();
+ if (newObjectsSize == 0) {
+ rpcFields->mObjectPositions.clear();
+ if (rpcFields->mFds) {
+ rpcFields->mFds->clear();
+ }
+ return OK;
+ }
+ while (rpcFields->mObjectPositions.size() > newObjectsSize) {
+ uint32_t pos = rpcFields->mObjectPositions.back();
+ rpcFields->mObjectPositions.pop_back();
+ const auto type = *reinterpret_cast<const RpcFields::ObjectType*>(mData + pos);
+ if (type == RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+ const auto fdIndex =
+ *reinterpret_cast<const int32_t*>(mData + pos + sizeof(RpcFields::ObjectType));
+ if (rpcFields->mFds == nullptr || fdIndex < 0 ||
+ static_cast<size_t>(fdIndex) >= rpcFields->mFds->size()) {
+ ALOGE("RPC Parcel contains invalid file descriptor index. index=%d fd_count=%zu",
+ fdIndex, rpcFields->mFds ? rpcFields->mFds->size() : 0);
+ return BAD_VALUE;
+ }
+ // In practice, this always removes the last element.
+ rpcFields->mFds->erase(rpcFields->mFds->begin() + fdIndex);
+ }
+ }
+ return OK;
+}
+
void Parcel::initState()
{
LOG_ALLOC("Parcel %p: initState", this);
@@ -2760,6 +3059,7 @@
kernelFields->mFdsKnown = true;
}
+#ifdef BINDER_WITH_KERNEL_IPC
size_t Parcel::getBlobAshmemSize() const
{
// This used to return the size of all blobs that were written to ashmem, now we're returning
@@ -2792,6 +3092,7 @@
}
return openAshmemSize;
}
+#endif // BINDER_WITH_KERNEL_IPC
// --- Parcel::Blob ---
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 528341e..1cd1fd3 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -32,6 +32,7 @@
#include <log/log.h>
#include <utils/Compat.h>
+#include "BuildFlags.h"
#include "FdTrigger.h"
#include "RpcSocketAddress.h"
#include "RpcState.h"
@@ -122,28 +123,36 @@
mProtocolVersion = version;
}
+void RpcServer::setSupportedFileDescriptorTransportModes(
+ const std::vector<RpcSession::FileDescriptorTransportMode>& modes) {
+ mSupportedFileDescriptorTransportModes.reset();
+ for (RpcSession::FileDescriptorTransportMode mode : modes) {
+ mSupportedFileDescriptorTransportModes.set(static_cast<size_t>(mode));
+ }
+}
+
void RpcServer::setRootObject(const sp<IBinder>& binder) {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
mRootObjectFactory = nullptr;
mRootObjectWeak = mRootObject = binder;
}
void RpcServer::setRootObjectWeak(const wp<IBinder>& binder) {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
mRootObject.clear();
mRootObjectFactory = nullptr;
mRootObjectWeak = binder;
}
void RpcServer::setPerSessionRootObject(
std::function<sp<IBinder>(const void*, size_t)>&& makeObject) {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
mRootObject.clear();
mRootObjectWeak.clear();
mRootObjectFactory = std::move(makeObject);
}
sp<IBinder> RpcServer::getRootObject() {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
bool hasWeak = mRootObjectWeak.unsafe_get();
sp<IBinder> ret = mRootObjectWeak.promote();
ALOGW_IF(hasWeak && ret == nullptr, "RpcServer root object is freed, returning nullptr");
@@ -151,7 +160,7 @@
}
std::vector<uint8_t> RpcServer::getCertificate(RpcCertificateFormat format) {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
return mCtx->getCertificate(format);
}
@@ -160,15 +169,17 @@
}
void RpcServer::start() {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
LOG_ALWAYS_FATAL_IF(mJoinThread.get(), "Already started!");
- mJoinThread = std::make_unique<std::thread>(&joinRpcServer, sp<RpcServer>::fromExisting(this));
+ mJoinThread =
+ std::make_unique<RpcMaybeThread>(&joinRpcServer, sp<RpcServer>::fromExisting(this));
+ rpcJoinIfSingleThreaded(*mJoinThread);
}
void RpcServer::join() {
{
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
LOG_ALWAYS_FATAL_IF(!mServer.ok(), "RpcServer must be setup to join.");
LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined");
mJoinThreadRunning = true;
@@ -196,24 +207,31 @@
LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
{
- std::lock_guard<std::mutex> _l(mLock);
- std::thread thread =
- std::thread(&RpcServer::establishConnection, sp<RpcServer>::fromExisting(this),
- std::move(clientFd), addr, addrLen);
- mConnectingThreads[thread.get_id()] = std::move(thread);
+ RpcMutexLockGuard _l(mLock);
+ RpcMaybeThread thread = RpcMaybeThread(&RpcServer::establishConnection,
+ sp<RpcServer>::fromExisting(this),
+ std::move(clientFd), addr, addrLen);
+
+ auto& threadRef = mConnectingThreads[thread.get_id()];
+ threadRef = std::move(thread);
+ rpcJoinIfSingleThreaded(threadRef);
}
}
LOG_RPC_DETAIL("RpcServer::join exiting with %s", statusToString(status).c_str());
- {
- std::lock_guard<std::mutex> _l(mLock);
+ if constexpr (kEnableRpcThreads) {
+ RpcMutexLockGuard _l(mLock);
mJoinThreadRunning = false;
+ } else {
+ // Multi-threaded builds clear this in shutdown(), but we need it valid
+ // so the loop above exits cleanly
+ mShutdownTrigger = nullptr;
}
mShutdownCv.notify_all();
}
bool RpcServer::shutdown() {
- std::unique_lock<std::mutex> _l(mLock);
+ RpcMutexUniqueLock _l(mLock);
if (mShutdownTrigger == nullptr) {
LOG_RPC_DETAIL("Cannot shutdown. No shutdown trigger installed (already shutdown?)");
return false;
@@ -224,10 +242,16 @@
for (auto& [id, session] : mSessions) {
(void)id;
// server lock is a more general lock
- std::lock_guard<std::mutex> _lSession(session->mMutex);
+ RpcMutexLockGuard _lSession(session->mMutex);
session->mShutdownTrigger->trigger();
}
+ if constexpr (!kEnableRpcThreads) {
+ // In single-threaded mode we're done here, everything else that
+ // needs to happen should be at the end of RpcServer::join()
+ return true;
+ }
+
while (mJoinThreadRunning || !mConnectingThreads.empty() || !mSessions.empty()) {
if (std::cv_status::timeout == mShutdownCv.wait_for(_l, std::chrono::seconds(1))) {
ALOGE("Waiting for RpcServer to shut down (1s w/o progress). Join thread running: %d, "
@@ -255,7 +279,7 @@
}
std::vector<sp<RpcSession>> RpcServer::listSessions() {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
std::vector<sp<RpcSession>> sessions;
for (auto& [id, session] : mSessions) {
(void)id;
@@ -265,7 +289,7 @@
}
size_t RpcServer::numUninitializedSessions() {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
return mConnectingThreads.size();
}
@@ -292,7 +316,7 @@
if (status == OK) {
iovec iov{&header, sizeof(header)};
status = client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1,
- std::nullopt);
+ std::nullopt, /*ancillaryFds=*/nullptr);
if (status != OK) {
ALOGE("Failed to read ID for client connecting to RPC server: %s",
statusToString(status).c_str());
@@ -307,7 +331,7 @@
sessionId.resize(header.sessionIdSize);
iovec iov{sessionId.data(), sessionId.size()};
status = client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1,
- std::nullopt);
+ std::nullopt, /*ancillaryFds=*/nullptr);
if (status != OK) {
ALOGE("Failed to read session ID for client connecting to RPC server: %s",
statusToString(status).c_str());
@@ -338,7 +362,7 @@
iovec iov{&response, sizeof(response)};
status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &iov, 1,
- std::nullopt);
+ std::nullopt, nullptr);
if (status != OK) {
ALOGE("Failed to send new session response: %s", statusToString(status).c_str());
// still need to cleanup before we can return
@@ -346,12 +370,12 @@
}
}
- std::thread thisThread;
+ RpcMaybeThread thisThread;
sp<RpcSession> session;
{
- std::unique_lock<std::mutex> _l(server->mLock);
+ RpcMutexUniqueLock _l(server->mLock);
- auto threadId = server->mConnectingThreads.find(std::this_thread::get_id());
+ auto threadId = server->mConnectingThreads.find(rpc_this_thread::get_id());
LOG_ALWAYS_FATAL_IF(threadId == server->mConnectingThreads.end(),
"Must establish connection on owned thread");
thisThread = std::move(threadId->second);
@@ -396,6 +420,17 @@
session->setMaxIncomingThreads(server->mMaxThreads);
if (!session->setProtocolVersion(protocolVersion)) return;
+ if (server->mSupportedFileDescriptorTransportModes.test(
+ header.fileDescriptorTransportMode)) {
+ session->setFileDescriptorTransportMode(
+ static_cast<RpcSession::FileDescriptorTransportMode>(
+ header.fileDescriptorTransportMode));
+ } else {
+ ALOGE("Rejecting connection: FileDescriptorTransportMode is not supported: %hhu",
+ header.fileDescriptorTransportMode);
+ return;
+ }
+
// if null, falls back to server root
sp<IBinder> sessionSpecificRoot;
if (server->mRootObjectFactory != nullptr) {
@@ -486,7 +521,7 @@
LOG_RPC_DETAIL("Dropping session with address %s",
base::HexString(id.data(), id.size()).c_str());
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
auto it = mSessions.find(id);
LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %s",
base::HexString(id.data(), id.size()).c_str());
@@ -500,17 +535,17 @@
}
bool RpcServer::hasServer() {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
return mServer.ok();
}
unique_fd RpcServer::releaseServer() {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
return std::move(mServer);
}
status_t RpcServer::setupExternalServer(base::unique_fd serverFd) {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
if (mServer.ok()) {
ALOGE("Each RpcServer can only have one server.");
return INVALID_OPERATION;
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 7ba08ed..2d9c933 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -21,7 +21,6 @@
#include <dlfcn.h>
#include <inttypes.h>
#include <poll.h>
-#include <pthread.h>
#include <unistd.h>
#include <string_view>
@@ -60,7 +59,7 @@
RpcSession::~RpcSession() {
LOG_RPC_DETAIL("RpcSession destroyed %p", this);
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
LOG_ALWAYS_FATAL_IF(mConnections.mIncoming.size() != 0,
"Should not be able to destroy a session with servers in use.");
}
@@ -77,7 +76,7 @@
}
void RpcSession::setMaxIncomingThreads(size_t threads) {
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
"Must set max incoming threads before setting up connections, but has %zu "
"client(s) and %zu server(s)",
@@ -86,12 +85,12 @@
}
size_t RpcSession::getMaxIncomingThreads() {
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
return mMaxIncomingThreads;
}
void RpcSession::setMaxOutgoingThreads(size_t threads) {
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
"Must set max outgoing threads before setting up connections, but has %zu "
"client(s) and %zu server(s)",
@@ -100,7 +99,7 @@
}
size_t RpcSession::getMaxOutgoingThreads() {
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
return mMaxOutgoingThreads;
}
@@ -113,7 +112,7 @@
return false;
}
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
if (mProtocolVersion && version > *mProtocolVersion) {
ALOGE("Cannot upgrade explicitly capped protocol version %u to newer version %u",
*mProtocolVersion, version);
@@ -125,10 +124,18 @@
}
std::optional<uint32_t> RpcSession::getProtocolVersion() {
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
return mProtocolVersion;
}
+void RpcSession::setFileDescriptorTransportMode(FileDescriptorTransportMode mode) {
+ mFileDescriptorTransportMode = mode;
+}
+
+RpcSession::FileDescriptorTransportMode RpcSession::getFileDescriptorTransportMode() {
+ return mFileDescriptorTransportMode;
+}
+
status_t RpcSession::setupUnixDomainClient(const char* path) {
return setupSocketClient(UnixSocketAddress(path));
}
@@ -201,7 +208,7 @@
}
bool RpcSession::shutdownAndWait(bool wait) {
- std::unique_lock<std::mutex> _l(mMutex);
+ RpcMutexUniqueLock _l(mMutex);
LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr, "Shutdown trigger not installed");
mShutdownTrigger->trigger();
@@ -214,6 +221,7 @@
}
_l.unlock();
+
mRpcBinderState->clear();
return true;
@@ -248,7 +256,7 @@
status_t RpcSession::readId() {
{
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
LOG_ALWAYS_FATAL_IF(mForServer != nullptr, "Can only update ID for client.");
}
@@ -274,7 +282,7 @@
mCv.notify_all();
}
-void RpcSession::WaitForShutdownListener::waitForShutdown(std::unique_lock<std::mutex>& lock,
+void RpcSession::WaitForShutdownListener::waitForShutdown(RpcMutexUniqueLock& lock,
const sp<RpcSession>& session) {
while (session->mConnections.mIncoming.size() > 0) {
if (std::cv_status::timeout == mCv.wait_for(lock, std::chrono::seconds(1))) {
@@ -285,11 +293,11 @@
}
}
-void RpcSession::preJoinThreadOwnership(std::thread thread) {
- LOG_ALWAYS_FATAL_IF(thread.get_id() != std::this_thread::get_id(), "Must own this thread");
+void RpcSession::preJoinThreadOwnership(RpcMaybeThread thread) {
+ LOG_ALWAYS_FATAL_IF(thread.get_id() != rpc_this_thread::get_id(), "Must own this thread");
{
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
mConnections.mThreads[thread.get_id()] = std::move(thread);
}
}
@@ -396,8 +404,8 @@
sp<RpcSession::EventListener> listener;
{
- std::lock_guard<std::mutex> _l(session->mMutex);
- auto it = session->mConnections.mThreads.find(std::this_thread::get_id());
+ RpcMutexLockGuard _l(session->mMutex);
+ auto it = session->mConnections.mThreads.find(rpc_this_thread::get_id());
LOG_ALWAYS_FATAL_IF(it == session->mConnections.mThreads.end());
it->second.detach();
session->mConnections.mThreads.erase(it);
@@ -430,7 +438,7 @@
status_t RpcSession::setupClient(const std::function<status_t(const std::vector<uint8_t>& sessionId,
bool incoming)>& connectAndInit) {
{
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
LOG_ALWAYS_FATAL_IF(mConnections.mOutgoing.size() != 0,
"Must only setup session once, but already has %zu clients",
mConnections.mOutgoing.size());
@@ -492,7 +500,11 @@
return status;
}
+#ifdef BINDER_RPC_SINGLE_THREADED
+ constexpr size_t outgoingThreads = 1;
+#else // BINDER_RPC_SINGLE_THREADED
size_t outgoingThreads = std::min(numThreadsAvailable, mMaxOutgoingThreads);
+#endif // BINDER_RPC_SINGLE_THREADED
ALOGI_IF(outgoingThreads != numThreadsAvailable,
"Server hints client to start %zu outgoing threads, but client will only start %zu "
"because it is preconfigured to start at most %zu outgoing threads.",
@@ -606,6 +618,7 @@
RpcConnectionHeader header{
.version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
.options = 0,
+ .fileDescriptorTransportMode = static_cast<uint8_t>(mFileDescriptorTransportMode),
.sessionIdSize = static_cast<uint16_t>(sessionId.size()),
};
@@ -614,8 +627,8 @@
}
iovec headerIov{&header, sizeof(header)};
- auto sendHeaderStatus =
- server->interruptableWriteFully(mShutdownTrigger.get(), &headerIov, 1, std::nullopt);
+ auto sendHeaderStatus = server->interruptableWriteFully(mShutdownTrigger.get(), &headerIov, 1,
+ std::nullopt, nullptr);
if (sendHeaderStatus != OK) {
ALOGE("Could not write connection header to socket: %s",
statusToString(sendHeaderStatus).c_str());
@@ -625,8 +638,9 @@
if (sessionId.size() > 0) {
iovec sessionIov{const_cast<void*>(static_cast<const void*>(sessionId.data())),
sessionId.size()};
- auto sendSessionIdStatus = server->interruptableWriteFully(mShutdownTrigger.get(),
- &sessionIov, 1, std::nullopt);
+ auto sendSessionIdStatus =
+ server->interruptableWriteFully(mShutdownTrigger.get(), &sessionIov, 1,
+ std::nullopt, nullptr);
if (sendSessionIdStatus != OK) {
ALOGE("Could not write session ID ('%s') to socket: %s",
base::HexString(sessionId.data(), sessionId.size()).c_str(),
@@ -645,14 +659,14 @@
}
status_t RpcSession::addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport) {
- std::mutex mutex;
- std::condition_variable joinCv;
- std::unique_lock<std::mutex> lock(mutex);
- std::thread thread;
+ RpcMutex mutex;
+ RpcConditionVariable joinCv;
+ RpcMutexUniqueLock lock(mutex);
+ RpcMaybeThread thread;
sp<RpcSession> thiz = sp<RpcSession>::fromExisting(this);
bool ownershipTransferred = false;
- thread = std::thread([&]() {
- std::unique_lock<std::mutex> threadLock(mutex);
+ thread = RpcMaybeThread([&]() {
+ RpcMutexUniqueLock threadLock(mutex);
std::unique_ptr<RpcTransport> movedRpcTransport = std::move(rpcTransport);
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
sp<RpcSession> session = thiz;
@@ -668,6 +682,7 @@
RpcSession::join(std::move(session), std::move(setupResult));
});
+ rpcJoinIfSingleThreaded(thread);
joinCv.wait(lock, [&] { return ownershipTransferred; });
LOG_ALWAYS_FATAL_IF(!ownershipTransferred);
return OK;
@@ -687,9 +702,9 @@
status_t RpcSession::addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport, bool init) {
sp<RpcConnection> connection = sp<RpcConnection>::make();
{
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
connection->rpcTransport = std::move(rpcTransport);
- connection->exclusiveTid = base::GetThreadId();
+ connection->exclusiveTid = rpcGetThreadId();
mConnections.mOutgoing.push_back(connection);
}
@@ -726,7 +741,7 @@
sp<RpcSession::RpcConnection> RpcSession::assignIncomingConnectionToThisThread(
std::unique_ptr<RpcTransport> rpcTransport) {
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
if (mConnections.mIncoming.size() >= mMaxIncomingThreads) {
ALOGE("Cannot add thread to session with %zu threads (max is set to %zu)",
@@ -744,7 +759,7 @@
sp<RpcConnection> session = sp<RpcConnection>::make();
session->rpcTransport = std::move(rpcTransport);
- session->exclusiveTid = base::GetThreadId();
+ session->exclusiveTid = rpcGetThreadId();
mConnections.mIncoming.push_back(session);
mConnections.mMaxIncoming = mConnections.mIncoming.size();
@@ -753,7 +768,7 @@
}
bool RpcSession::removeIncomingConnection(const sp<RpcConnection>& connection) {
- std::unique_lock<std::mutex> _l(mMutex);
+ RpcMutexUniqueLock _l(mMutex);
if (auto it =
std::find(mConnections.mIncoming.begin(), mConnections.mIncoming.end(), connection);
it != mConnections.mIncoming.end()) {
@@ -771,7 +786,7 @@
}
void RpcSession::clearConnectionTid(const sp<RpcConnection>& connection) {
- std::unique_lock<std::mutex> _l(mMutex);
+ RpcMutexUniqueLock _l(mMutex);
connection->exclusiveTid = std::nullopt;
if (mConnections.mWaitingThreads > 0) {
_l.unlock();
@@ -789,8 +804,8 @@
connection->mConnection = nullptr;
connection->mReentrant = false;
- uint64_t tid = base::GetThreadId();
- std::unique_lock<std::mutex> _l(session->mMutex);
+ uint64_t tid = rpcGetThreadId();
+ RpcMutexUniqueLock _l(session->mMutex);
session->mConnections.mWaitingThreads++;
while (true) {
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 419df86..bde3d90 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -21,6 +21,7 @@
#include <android-base/hex.h>
#include <android-base/macros.h>
#include <android-base/scopeguard.h>
+#include <android-base/stringprintf.h>
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/RpcServer.h>
@@ -35,7 +36,7 @@
namespace android {
-using base::ScopeGuard;
+using base::StringPrintf;
#if RPC_FLAKE_PRONE
void rpcMaybeWaitToFlake() {
@@ -43,13 +44,22 @@
[[clang::no_destroy]] static std::mutex m;
unsigned num;
{
- std::lock_guard<std::mutex> lock(m);
+ RpcMutexLockGuard lock(m);
num = r();
}
if (num % 10 == 0) usleep(num % 1000);
}
#endif
+static bool enableAncillaryFds(RpcSession::FileDescriptorTransportMode mode) {
+ switch (mode) {
+ case RpcSession::FileDescriptorTransportMode::NONE:
+ return false;
+ case RpcSession::FileDescriptorTransportMode::UNIX:
+ return true;
+ }
+}
+
RpcState::RpcState() {}
RpcState::~RpcState() {}
@@ -78,7 +88,7 @@
return INVALID_OPERATION;
}
- std::lock_guard<std::mutex> _l(mNodeMutex);
+ RpcMutexLockGuard _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT;
// TODO(b/182939933): maybe move address out of BpBinder, and keep binder->address map
@@ -154,7 +164,7 @@
return BAD_VALUE;
}
- std::lock_guard<std::mutex> _l(mNodeMutex);
+ RpcMutexLockGuard _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT;
if (auto it = mNodeForAddress.find(address); it != mNodeForAddress.end()) {
@@ -189,7 +199,7 @@
// extra reference counting packets now.
if (binder->remoteBinder()) return OK;
- std::unique_lock<std::mutex> _l(mNodeMutex);
+ RpcMutexUniqueLock _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT;
auto it = mNodeForAddress.find(address);
@@ -217,17 +227,17 @@
}
size_t RpcState::countBinders() {
- std::lock_guard<std::mutex> _l(mNodeMutex);
+ RpcMutexLockGuard _l(mNodeMutex);
return mNodeForAddress.size();
}
void RpcState::dump() {
- std::lock_guard<std::mutex> _l(mNodeMutex);
+ RpcMutexLockGuard _l(mNodeMutex);
dumpLocked();
}
void RpcState::clear() {
- std::unique_lock<std::mutex> _l(mNodeMutex);
+ RpcMutexUniqueLock _l(mNodeMutex);
if (mTerminated) {
LOG_ALWAYS_FATAL_IF(!mNodeForAddress.empty(),
@@ -310,9 +320,11 @@
mData.reset(new (std::nothrow) uint8_t[size]);
}
-status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>>& altPoll) {
+status_t RpcState::rpcSend(
+ const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+ const char* what, iovec* iovs, int niovs,
+ const std::optional<android::base::function_ref<status_t()>>& altPoll,
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
for (int i = 0; i < niovs; i++) {
LOG_RPC_DETAIL("Sending %s (part %d of %d) on RpcTransport %p: %s",
what, i + 1, niovs, connection->rpcTransport.get(),
@@ -321,7 +333,8 @@
if (status_t status =
connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(),
- iovs, niovs, altPoll);
+ iovs, niovs, altPoll,
+ ancillaryFds);
status != OK) {
LOG_RPC_DETAIL("Failed to write %s (%d iovs) on RpcTransport %p, error: %s", what, niovs,
connection->rpcTransport.get(), statusToString(status).c_str());
@@ -332,11 +345,14 @@
return OK;
}
-status_t RpcState::rpcRec(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs) {
+status_t RpcState::rpcRec(
+ const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+ const char* what, iovec* iovs, int niovs,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
if (status_t status =
connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.get(),
- iovs, niovs, std::nullopt);
+ iovs, niovs, std::nullopt,
+ ancillaryFds);
status != OK) {
LOG_RPC_DETAIL("Failed to read %s (%d iovs) on RpcTransport %p, error: %s", what, niovs,
connection->rpcTransport.get(), statusToString(status).c_str());
@@ -356,7 +372,7 @@
const sp<RpcSession>& session, uint32_t* version) {
RpcNewSessionResponse response;
iovec iov{&response, sizeof(response)};
- if (status_t status = rpcRec(connection, session, "new session response", &iov, 1);
+ if (status_t status = rpcRec(connection, session, "new session response", &iov, 1, nullptr);
status != OK) {
return status;
}
@@ -377,7 +393,8 @@
const sp<RpcSession>& session) {
RpcOutgoingConnectionInit init;
iovec iov{&init, sizeof(init)};
- if (status_t status = rpcRec(connection, session, "connection init", &iov, 1); status != OK)
+ if (status_t status = rpcRec(connection, session, "connection init", &iov, 1, nullptr);
+ status != OK)
return status;
static_assert(sizeof(init.msg) == sizeof(RPC_CONNECTION_INIT_OKAY));
@@ -449,20 +466,12 @@
status_t RpcState::transact(const sp<RpcSession::RpcConnection>& connection,
const sp<IBinder>& binder, uint32_t code, const Parcel& data,
const sp<RpcSession>& session, Parcel* reply, uint32_t flags) {
- if (!data.isForRpc()) {
- ALOGE("Refusing to send RPC with parcel not crafted for RPC call on binder %p code "
- "%" PRIu32,
- binder.get(), code);
- return BAD_TYPE;
+ std::string errorMsg;
+ if (status_t status = validateParcel(session, data, &errorMsg); status != OK) {
+ ALOGE("Refusing to send RPC on binder %p code %" PRIu32 ": Parcel %p failed validation: %s",
+ binder.get(), code, &data, errorMsg.c_str());
+ return status;
}
-
- if (data.objectsCount() != 0) {
- ALOGE("Parcel at %p has attached objects but is being used in an RPC call on binder %p "
- "code %" PRIu32,
- &data, binder.get(), code);
- return BAD_TYPE;
- }
-
uint64_t address;
if (status_t status = onBinderLeaving(session, binder, &address); status != OK) return status;
@@ -478,7 +487,7 @@
uint64_t asyncNumber = 0;
if (address != 0) {
- std::unique_lock<std::mutex> _l(mNodeMutex);
+ RpcMutexUniqueLock _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
auto it = mNodeForAddress.find(address);
LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
@@ -494,9 +503,11 @@
}
}
- // objectTable always empty for now. Will be populated from `data` soon.
- std::vector<uint32_t> objectTable;
- Span<const uint32_t> objectTableSpan = {objectTable.data(), objectTable.size()};
+ auto* rpcFields = data.maybeRpcFields();
+ LOG_ALWAYS_FATAL_IF(rpcFields == nullptr);
+
+ Span<const uint32_t> objectTableSpan = Span<const uint32_t>{rpcFields->mObjectPositions.data(),
+ rpcFields->mObjectPositions.size()};
uint32_t bodySize;
LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(sizeof(RpcWireTransaction), data.dataSize(),
@@ -532,25 +543,25 @@
{const_cast<uint8_t*>(data.data()), data.dataSize()},
objectTableSpan.toIovec(),
};
- if (status_t status = rpcSend(connection, session, "transaction", iovs, arraysize(iovs),
- [&] {
- if (waitUs > kWaitLogUs) {
- ALOGE("Cannot send command, trying to process pending "
- "refcounts. Waiting %zuus. Too "
- "many oneway calls?",
- waitUs);
- }
+ if (status_t status = rpcSend(
+ connection, session, "transaction", iovs, arraysize(iovs),
+ [&] {
+ if (waitUs > kWaitLogUs) {
+ ALOGE("Cannot send command, trying to process pending refcounts. Waiting "
+ "%zuus. Too many oneway calls?",
+ waitUs);
+ }
- if (waitUs > 0) {
- usleep(waitUs);
- waitUs = std::min(kWaitMaxUs, waitUs * 2);
- } else {
- waitUs = 1;
- }
+ if (waitUs > 0) {
+ usleep(waitUs);
+ waitUs = std::min(kWaitMaxUs, waitUs * 2);
+ } else {
+ waitUs = 1;
+ }
- return drainCommands(connection, session,
- CommandType::CONTROL_ONLY);
- });
+ return drainCommands(connection, session, CommandType::CONTROL_ONLY);
+ },
+ rpcFields->mFds.get());
status != OK) {
// TODO(b/167966510): need to undo onBinderLeaving - we know the
// refcount isn't successfully transferred.
@@ -581,18 +592,26 @@
status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, Parcel* reply) {
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>> ancillaryFds;
RpcWireHeader command;
while (true) {
iovec iov{&command, sizeof(command)};
- if (status_t status = rpcRec(connection, session, "command header (for reply)", &iov, 1);
+ if (status_t status = rpcRec(connection, session, "command header (for reply)", &iov, 1,
+ enableAncillaryFds(session->getFileDescriptorTransportMode())
+ ? &ancillaryFds
+ : nullptr);
status != OK)
return status;
if (command.command == RPC_COMMAND_REPLY) break;
- if (status_t status = processCommand(connection, session, command, CommandType::ANY);
+ if (status_t status = processCommand(connection, session, command, CommandType::ANY,
+ std::move(ancillaryFds));
status != OK)
return status;
+
+ // Reset to avoid spurious use-after-move warning from clang-tidy.
+ ancillaryFds = decltype(ancillaryFds)();
}
const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());
@@ -614,21 +633,33 @@
{&rpcReply, rpcReplyWireSize},
{data.data(), data.size()},
};
- if (status_t status = rpcRec(connection, session, "reply body", iovs, arraysize(iovs));
+ if (status_t status = rpcRec(connection, session, "reply body", iovs, arraysize(iovs), nullptr);
status != OK)
return status;
+
if (rpcReply.status != OK) return rpcReply.status;
Span<const uint8_t> parcelSpan = {data.data(), data.size()};
+ Span<const uint32_t> objectTableSpan;
if (session->getProtocolVersion().value() >=
RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(rpcReply.parcelDataSize);
- LOG_ALWAYS_FATAL_IF(objectTableBytes.size > 0, "Non-empty object table not supported yet.");
+ std::optional<Span<const uint32_t>> maybeSpan =
+ objectTableBytes.reinterpret<const uint32_t>();
+ if (!maybeSpan.has_value()) {
+ ALOGE("Bad object table size inferred from RpcWireReply. Saw bodySize=%" PRId32
+ " sizeofHeader=%zu parcelSize=%" PRId32 " objectTableBytesSize=%zu. Terminating!",
+ command.bodySize, rpcReplyWireSize, rpcReply.parcelDataSize,
+ objectTableBytes.size);
+ return BAD_VALUE;
+ }
+ objectTableSpan = *maybeSpan;
}
data.release();
- reply->rpcSetDataReference(session, parcelSpan.data, parcelSpan.size, cleanup_reply_data);
- return OK;
+ return reply->rpcSetDataReference(session, parcelSpan.data, parcelSpan.size,
+ objectTableSpan.data, objectTableSpan.size,
+ std::move(ancillaryFds), cleanup_reply_data);
}
status_t RpcState::sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& connection,
@@ -639,7 +670,7 @@
};
{
- std::lock_guard<std::mutex> _l(mNodeMutex);
+ RpcMutexLockGuard _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
auto it = mNodeForAddress.find(addr);
LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
@@ -671,13 +702,17 @@
const sp<RpcSession>& session, CommandType type) {
LOG_RPC_DETAIL("getAndExecuteCommand on RpcTransport %p", connection->rpcTransport.get());
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>> ancillaryFds;
RpcWireHeader command;
iovec iov{&command, sizeof(command)};
- if (status_t status = rpcRec(connection, session, "command header (for server)", &iov, 1);
+ if (status_t status =
+ rpcRec(connection, session, "command header (for server)", &iov, 1,
+ enableAncillaryFds(session->getFileDescriptorTransportMode()) ? &ancillaryFds
+ : nullptr);
status != OK)
return status;
- return processCommand(connection, session, command, type);
+ return processCommand(connection, session, command, type, std::move(ancillaryFds));
}
status_t RpcState::drainCommands(const sp<RpcSession::RpcConnection>& connection,
@@ -693,9 +728,11 @@
return OK;
}
-status_t RpcState::processCommand(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const RpcWireHeader& command,
- CommandType type) {
+status_t RpcState::processCommand(
+ const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+ const RpcWireHeader& command, CommandType type,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds) {
+#ifdef BINDER_WITH_KERNEL_IPC
IPCThreadState* kernelBinderState = IPCThreadState::selfOrNull();
IPCThreadState::SpGuard spGuard{
.address = __builtin_frame_address(0),
@@ -705,16 +742,18 @@
if (kernelBinderState != nullptr) {
origGuard = kernelBinderState->pushGetCallingSpGuard(&spGuard);
}
- ScopeGuard guardUnguard = [&]() {
+
+ base::ScopeGuard guardUnguard = [&]() {
if (kernelBinderState != nullptr) {
kernelBinderState->restoreGetCallingSpGuard(origGuard);
}
};
+#endif // BINDER_WITH_KERNEL_IPC
switch (command.command) {
case RPC_COMMAND_TRANSACT:
if (type != CommandType::ANY) return BAD_TYPE;
- return processTransact(connection, session, command);
+ return processTransact(connection, session, command, std::move(ancillaryFds));
case RPC_COMMAND_DEC_STRONG:
return processDecStrong(connection, session, command);
}
@@ -728,8 +767,10 @@
(void)session->shutdownAndWait(false);
return DEAD_OBJECT;
}
-status_t RpcState::processTransact(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const RpcWireHeader& command) {
+status_t RpcState::processTransact(
+ const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+ const RpcWireHeader& command,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds) {
LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_TRANSACT, "command: %d", command.command);
CommandData transactionData(command.bodySize);
@@ -737,10 +778,12 @@
return NO_MEMORY;
}
iovec iov{transactionData.data(), transactionData.size()};
- if (status_t status = rpcRec(connection, session, "transaction body", &iov, 1); status != OK)
+ if (status_t status = rpcRec(connection, session, "transaction body", &iov, 1, nullptr);
+ status != OK)
return status;
- return processTransactInternal(connection, session, std::move(transactionData));
+ return processTransactInternal(connection, session, std::move(transactionData),
+ std::move(ancillaryFds));
}
static void do_nothing_to_transact_data(Parcel* p, const uint8_t* data, size_t dataSize,
@@ -752,9 +795,10 @@
(void)objectsCount;
}
-status_t RpcState::processTransactInternal(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session,
- CommandData transactionData) {
+status_t RpcState::processTransactInternal(
+ const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+ CommandData transactionData,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds) {
// for 'recursive' calls to this, we have already read and processed the
// binder from the transaction data and taken reference counts into account,
// so it is cached here.
@@ -798,7 +842,7 @@
(void)session->shutdownAndWait(false);
replyStatus = BAD_VALUE;
} else if (oneway) {
- std::unique_lock<std::mutex> _l(mNodeMutex);
+ RpcMutexUniqueLock _l(mNodeMutex);
auto it = mNodeForAddress.find(addr);
if (it->second.binder.promote() != target) {
ALOGE("Binder became invalid during transaction. Bad client? %" PRIu64, addr);
@@ -845,11 +889,21 @@
Span<const uint8_t> parcelSpan = {transaction->data,
transactionData.size() -
offsetof(RpcWireTransaction, data)};
- if (session->getProtocolVersion().value() >=
+ Span<const uint32_t> objectTableSpan;
+ if (session->getProtocolVersion().value() >
RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(transaction->parcelDataSize);
- LOG_ALWAYS_FATAL_IF(objectTableBytes.size > 0,
- "Non-empty object table not supported yet.");
+ std::optional<Span<const uint32_t>> maybeSpan =
+ objectTableBytes.reinterpret<const uint32_t>();
+ if (!maybeSpan.has_value()) {
+ ALOGE("Bad object table size inferred from RpcWireTransaction. Saw bodySize=%zu "
+ "sizeofHeader=%zu parcelSize=%" PRId32
+ " objectTableBytesSize=%zu. Terminating!",
+ transactionData.size(), sizeof(RpcWireTransaction),
+ transaction->parcelDataSize, objectTableBytes.size);
+ return BAD_VALUE;
+ }
+ objectTableSpan = *maybeSpan;
}
Parcel data;
@@ -857,47 +911,53 @@
// only holds onto it for the duration of this function call. Parcel will be
// deleted before the 'transactionData' object.
- data.rpcSetDataReference(session, parcelSpan.data, parcelSpan.size,
- do_nothing_to_transact_data);
+ replyStatus =
+ data.rpcSetDataReference(session, parcelSpan.data, parcelSpan.size,
+ objectTableSpan.data, objectTableSpan.size,
+ std::move(ancillaryFds), do_nothing_to_transact_data);
+ // Reset to avoid spurious use-after-move warning from clang-tidy.
+ ancillaryFds = std::remove_reference<decltype(ancillaryFds)>::type();
- if (target) {
- bool origAllowNested = connection->allowNested;
- connection->allowNested = !oneway;
+ if (replyStatus == OK) {
+ if (target) {
+ bool origAllowNested = connection->allowNested;
+ connection->allowNested = !oneway;
- replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
+ replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
- connection->allowNested = origAllowNested;
- } else {
- LOG_RPC_DETAIL("Got special transaction %u", transaction->code);
+ connection->allowNested = origAllowNested;
+ } else {
+ LOG_RPC_DETAIL("Got special transaction %u", transaction->code);
- switch (transaction->code) {
- case RPC_SPECIAL_TRANSACT_GET_MAX_THREADS: {
- replyStatus = reply.writeInt32(session->getMaxIncomingThreads());
- break;
- }
- case RPC_SPECIAL_TRANSACT_GET_SESSION_ID: {
- // for client connections, this should always report the value
- // originally returned from the server, so this is asserting
- // that it exists
- replyStatus = reply.writeByteVector(session->mId);
- break;
- }
- default: {
- sp<RpcServer> server = session->server();
- if (server) {
- switch (transaction->code) {
- case RPC_SPECIAL_TRANSACT_GET_ROOT: {
- sp<IBinder> root = session->mSessionSpecificRootObject
- ?: server->getRootObject();
- replyStatus = reply.writeStrongBinder(root);
- break;
+ switch (transaction->code) {
+ case RPC_SPECIAL_TRANSACT_GET_MAX_THREADS: {
+ replyStatus = reply.writeInt32(session->getMaxIncomingThreads());
+ break;
+ }
+ case RPC_SPECIAL_TRANSACT_GET_SESSION_ID: {
+ // for client connections, this should always report the value
+ // originally returned from the server, so this is asserting
+ // that it exists
+ replyStatus = reply.writeByteVector(session->mId);
+ break;
+ }
+ default: {
+ sp<RpcServer> server = session->server();
+ if (server) {
+ switch (transaction->code) {
+ case RPC_SPECIAL_TRANSACT_GET_ROOT: {
+ sp<IBinder> root = session->mSessionSpecificRootObject
+ ?: server->getRootObject();
+ replyStatus = reply.writeStrongBinder(root);
+ break;
+ }
+ default: {
+ replyStatus = UNKNOWN_TRANSACTION;
+ }
}
- default: {
- replyStatus = UNKNOWN_TRANSACTION;
- }
+ } else {
+ ALOGE("Special command sent, but no server object attached.");
}
- } else {
- ALOGE("Special command sent, but no server object attached.");
}
}
}
@@ -923,7 +983,7 @@
// downside: asynchronous transactions may drown out synchronous
// transactions.
{
- std::unique_lock<std::mutex> _l(mNodeMutex);
+ RpcMutexUniqueLock _l(mNodeMutex);
auto it = mNodeForAddress.find(addr);
// last refcount dropped after this transaction happened
if (it == mNodeForAddress.end()) return OK;
@@ -969,11 +1029,22 @@
replyStatus = flushExcessBinderRefs(session, addr, target);
}
+ std::string errorMsg;
+ if (status_t status = validateParcel(session, reply, &errorMsg); status != OK) {
+ ALOGE("Reply Parcel failed validation: %s", errorMsg.c_str());
+ // Forward the error to the client of the transaction.
+ reply.freeData();
+ reply.markForRpc(session);
+ replyStatus = status;
+ }
+
+ auto* rpcFields = reply.maybeRpcFields();
+ LOG_ALWAYS_FATAL_IF(rpcFields == nullptr);
+
const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());
- // objectTable always empty for now. Will be populated from `reply` soon.
- std::vector<uint32_t> objectTable;
- Span<const uint32_t> objectTableSpan = {objectTable.data(), objectTable.size()};
+ Span<const uint32_t> objectTableSpan = Span<const uint32_t>{rpcFields->mObjectPositions.data(),
+ rpcFields->mObjectPositions.size()};
uint32_t bodySize;
LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(rpcReplyWireSize, reply.dataSize(), &bodySize) ||
@@ -998,7 +1069,8 @@
{const_cast<uint8_t*>(reply.data()), reply.dataSize()},
objectTableSpan.toIovec(),
};
- return rpcSend(connection, session, "reply", iovs, arraysize(iovs), std::nullopt);
+ return rpcSend(connection, session, "reply", iovs, arraysize(iovs), std::nullopt,
+ rpcFields->mFds.get());
}
status_t RpcState::processDecStrong(const sp<RpcSession::RpcConnection>& connection,
@@ -1014,11 +1086,12 @@
RpcDecStrong body;
iovec iov{&body, sizeof(RpcDecStrong)};
- if (status_t status = rpcRec(connection, session, "dec ref body", &iov, 1); status != OK)
+ if (status_t status = rpcRec(connection, session, "dec ref body", &iov, 1, nullptr);
+ status != OK)
return status;
uint64_t addr = RpcWireAddress::toRaw(body.address);
- std::unique_lock<std::mutex> _l(mNodeMutex);
+ RpcMutexUniqueLock _l(mNodeMutex);
auto it = mNodeForAddress.find(addr);
if (it == mNodeForAddress.end()) {
ALOGE("Unknown binder address %" PRIu64 " for dec strong.", addr);
@@ -1055,6 +1128,50 @@
return OK;
}
+status_t RpcState::validateParcel(const sp<RpcSession>& session, const Parcel& parcel,
+ std::string* errorMsg) {
+ auto* rpcFields = parcel.maybeRpcFields();
+ if (rpcFields == nullptr) {
+ *errorMsg = "Parcel not crafted for RPC call";
+ return BAD_TYPE;
+ }
+
+ if (rpcFields->mSession != session) {
+ *errorMsg = "Parcel's session doesn't match";
+ return BAD_TYPE;
+ }
+
+ uint32_t protocolVersion = session->getProtocolVersion().value();
+ if (protocolVersion < RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE &&
+ !rpcFields->mObjectPositions.empty()) {
+ *errorMsg = StringPrintf("Parcel has attached objects but the session's protocol version "
+ "(%" PRIu32 ") is too old, must be at least %" PRIu32,
+ protocolVersion,
+ RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE);
+ return BAD_VALUE;
+ }
+
+ if (rpcFields->mFds && !rpcFields->mFds->empty()) {
+ switch (session->getFileDescriptorTransportMode()) {
+ case RpcSession::FileDescriptorTransportMode::NONE:
+ *errorMsg =
+ "Parcel has file descriptors, but no file descriptor transport is enabled";
+ return FDS_NOT_ALLOWED;
+ case RpcSession::FileDescriptorTransportMode::UNIX: {
+ constexpr size_t kMaxFdsPerMsg = 253;
+ if (rpcFields->mFds->size() > kMaxFdsPerMsg) {
+ *errorMsg = StringPrintf("Too many file descriptors in Parcel for unix "
+ "domain socket: %zu (max is %zu)",
+ rpcFields->mFds->size(), kMaxFdsPerMsg);
+ return BAD_VALUE;
+ }
+ }
+ }
+ }
+
+ return OK;
+}
+
sp<IBinder> RpcState::tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it) {
sp<IBinder> ref;
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 9cbe187..6fb2e4a 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -19,6 +19,7 @@
#include <binder/IBinder.h>
#include <binder/Parcel.h>
#include <binder/RpcSession.h>
+#include <binder/RpcThreads.h>
#include <map>
#include <optional>
@@ -181,26 +182,36 @@
[[nodiscard]] status_t rpcSend(
const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
const char* what, iovec* iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>>& altPoll);
- [[nodiscard]] status_t rpcRec(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const char* what, iovec* iovs,
- int niovs);
+ const std::optional<android::base::function_ref<status_t()>>& altPoll,
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds =
+ nullptr);
+ [[nodiscard]] status_t rpcRec(
+ const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+ const char* what, iovec* iovs, int niovs,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds = nullptr);
[[nodiscard]] status_t waitForReply(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, Parcel* reply);
- [[nodiscard]] status_t processCommand(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session,
- const RpcWireHeader& command, CommandType type);
- [[nodiscard]] status_t processTransact(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session,
- const RpcWireHeader& command);
- [[nodiscard]] status_t processTransactInternal(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session,
- CommandData transactionData);
+ [[nodiscard]] status_t processCommand(
+ const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+ const RpcWireHeader& command, CommandType type,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds);
+ [[nodiscard]] status_t processTransact(
+ const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+ const RpcWireHeader& command,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds);
+ [[nodiscard]] status_t processTransactInternal(
+ const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+ CommandData transactionData,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds);
[[nodiscard]] status_t processDecStrong(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session,
const RpcWireHeader& command);
+ // Whether `parcel` is compatible with `session`.
+ [[nodiscard]] static status_t validateParcel(const sp<RpcSession>& session,
+ const Parcel& parcel, std::string* errorMsg);
+
struct BinderNode {
// Two cases:
// A - local binder we are serving
@@ -258,7 +269,7 @@
// false - session shutdown, halt
[[nodiscard]] bool nodeProgressAsyncNumber(BinderNode* node);
- std::mutex mNodeMutex;
+ RpcMutex mNodeMutex;
bool mTerminated = false;
uint32_t mNextId = 0;
// binders known by both sides of a session
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index f9b73fc..7cc58cd 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -18,6 +18,7 @@
#include <log/log.h>
#include <poll.h>
+#include <stddef.h>
#include <binder/RpcTransportRaw.h>
@@ -28,6 +29,9 @@
namespace {
+// Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets.
+constexpr size_t kMaxFdsPerMsg = 253;
+
// RpcTransport with TLS disabled.
class RpcTransportRaw : public RpcTransport {
public:
@@ -85,15 +89,7 @@
bool havePolled = false;
while (true) {
- msghdr msg{
- .msg_iov = iovs,
- // posix uses int, glibc uses size_t. niovs is a
- // non-negative int and can be cast to either.
- .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
- };
- ssize_t processSize =
- TEMP_FAILURE_RETRY(sendOrReceiveFun(mSocket.get(), &msg, MSG_NOSIGNAL));
-
+ ssize_t processSize = sendOrReceiveFun(iovs, niovs);
if (processSize < 0) {
int savedErrno = errno;
@@ -145,16 +141,121 @@
status_t interruptableWriteFully(
FdTrigger* fdTrigger, iovec* iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>>& altPoll) override {
- return interruptableReadOrWrite(fdTrigger, iovs, niovs, sendmsg, "sendmsg", POLLOUT,
- altPoll);
+ const std::optional<android::base::function_ref<status_t()>>& altPoll,
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
+ override {
+ bool sentFds = false;
+ auto send = [&](iovec* iovs, int niovs) -> ssize_t {
+ if (ancillaryFds != nullptr && !ancillaryFds->empty() && !sentFds) {
+ if (ancillaryFds->size() > kMaxFdsPerMsg) {
+ // This shouldn't happen because we check the FD count in RpcState.
+ ALOGE("Saw too many file descriptors in RpcTransportCtxRaw: %zu (max is %zu). "
+ "Aborting session.",
+ ancillaryFds->size(), kMaxFdsPerMsg);
+ errno = EINVAL;
+ return -1;
+ }
+
+ // CMSG_DATA is not necessarily aligned, so we copy the FDs into a buffer and then
+ // use memcpy.
+ int fds[kMaxFdsPerMsg];
+ for (size_t i = 0; i < ancillaryFds->size(); i++) {
+ fds[i] = std::visit([](const auto& fd) { return fd.get(); },
+ ancillaryFds->at(i));
+ }
+ const size_t fdsByteSize = sizeof(int) * ancillaryFds->size();
+
+ alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(int) * kMaxFdsPerMsg)];
+
+ msghdr msg{
+ .msg_iov = iovs,
+ .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+ .msg_control = msgControlBuf,
+ .msg_controllen = sizeof(msgControlBuf),
+ };
+
+ cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(fdsByteSize);
+ memcpy(CMSG_DATA(cmsg), fds, fdsByteSize);
+
+ msg.msg_controllen = CMSG_SPACE(fdsByteSize);
+
+ ssize_t processedSize = TEMP_FAILURE_RETRY(
+ sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC));
+ if (processedSize > 0) {
+ sentFds = true;
+ }
+ return processedSize;
+ }
+
+ msghdr msg{
+ .msg_iov = iovs,
+ // posix uses int, glibc uses size_t. niovs is a
+ // non-negative int and can be cast to either.
+ .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+ };
+ return TEMP_FAILURE_RETRY(sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+ };
+ return interruptableReadOrWrite(fdTrigger, iovs, niovs, send, "sendmsg", POLLOUT, altPoll);
}
status_t interruptableReadFully(
FdTrigger* fdTrigger, iovec* iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>>& altPoll) override {
- return interruptableReadOrWrite(fdTrigger, iovs, niovs, recvmsg, "recvmsg", POLLIN,
- altPoll);
+ const std::optional<android::base::function_ref<status_t()>>& altPoll,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override {
+ auto recv = [&](iovec* iovs, int niovs) -> ssize_t {
+ if (ancillaryFds != nullptr) {
+ int fdBuffer[kMaxFdsPerMsg];
+ alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(fdBuffer))];
+
+ msghdr msg{
+ .msg_iov = iovs,
+ .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+ .msg_control = msgControlBuf,
+ .msg_controllen = sizeof(msgControlBuf),
+ };
+ ssize_t processSize =
+ TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+ if (processSize < 0) {
+ return -1;
+ }
+
+ for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ // NOTE: It is tempting to reinterpret_cast, but cmsg(3) explicitly asks
+ // application devs to memcpy the data to ensure memory alignment.
+ size_t dataLen = cmsg->cmsg_len - CMSG_LEN(0);
+ LOG_ALWAYS_FATAL_IF(dataLen > sizeof(fdBuffer)); // sanity check
+ memcpy(fdBuffer, CMSG_DATA(cmsg), dataLen);
+ size_t fdCount = dataLen / sizeof(int);
+ ancillaryFds->reserve(ancillaryFds->size() + fdCount);
+ for (size_t i = 0; i < fdCount; i++) {
+ ancillaryFds->emplace_back(base::unique_fd(fdBuffer[i]));
+ }
+ break;
+ }
+ }
+
+ if (msg.msg_flags & MSG_CTRUNC) {
+ ALOGE("msg was truncated. Aborting session.");
+ errno = EPIPE;
+ return -1;
+ }
+
+ return processSize;
+ }
+ msghdr msg{
+ .msg_iov = iovs,
+ // posix uses int, glibc uses size_t. niovs is a
+ // non-negative int and can be cast to either.
+ .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+ };
+ return TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+ };
+ return interruptableReadOrWrite(fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN, altPoll);
}
private:
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index ad5cb0f..09b5c17 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -282,10 +282,13 @@
status_t pollRead(void) override;
status_t interruptableWriteFully(
FdTrigger* fdTrigger, iovec* iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>>& altPoll) override;
+ const std::optional<android::base::function_ref<status_t()>>& altPoll,
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
+ override;
status_t interruptableReadFully(
FdTrigger* fdTrigger, iovec* iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>>& altPoll) override;
+ const std::optional<android::base::function_ref<status_t()>>& altPoll,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override;
private:
android::base::unique_fd mSocket;
@@ -313,7 +316,10 @@
status_t RpcTransportTls::interruptableWriteFully(
FdTrigger* fdTrigger, iovec* iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>>& altPoll) {
+ const std::optional<android::base::function_ref<status_t()>>& altPoll,
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
+ (void)ancillaryFds;
+
MAYBE_WAIT_IN_FLAKE_MODE;
if (niovs < 0) return BAD_VALUE;
@@ -356,7 +362,10 @@
status_t RpcTransportTls::interruptableReadFully(
FdTrigger* fdTrigger, iovec* iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>>& altPoll) {
+ const std::optional<android::base::function_ref<status_t()>>& altPoll,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
+ (void)ancillaryFds;
+
MAYBE_WAIT_IN_FLAKE_MODE;
if (niovs < 0) return BAD_VALUE;
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 7e2aa79..ff1b01a 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -45,7 +45,8 @@
struct RpcConnectionHeader {
uint32_t version; // maximum supported by caller
uint8_t options;
- uint8_t reservered[9];
+ uint8_t fileDescriptorTransportMode;
+ uint8_t reservered[8];
// Follows is sessionIdSize bytes.
// if size is 0, this is requesting a new session.
uint16_t sessionIdSize;
@@ -108,6 +109,10 @@
// serialization is like:
// |RpcWireHeader|struct desginated by 'command'| (over and over again)
+//
+// When file descriptors are included in out-of-band data (e.g. in unix domain
+// sockets), they are always paired with the RpcWireHeader bytes of the
+// transaction or reply the file descriptors belong to.
struct RpcWireHeader {
uint32_t command; // RPC_COMMAND_*
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index 7dcb70e..37c1262 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -60,6 +60,17 @@
size = offset;
return rest;
}
+
+ // Returns nullopt if the byte size of `this` isn't evenly divisible by sizeof(U).
+ template <typename U>
+ std::optional<Span<U>> reinterpret() const {
+ // Only allow casting from bytes for simplicity.
+ static_assert(std::is_same_v<std::remove_const_t<T>, uint8_t>);
+ if (size % sizeof(U) != 0) {
+ return std::nullopt;
+ }
+ return Span<U>{reinterpret_cast<U*>(data), size / sizeof(U)};
+ }
};
} // namespace android
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 0345a5d..32b0ded 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -608,8 +608,12 @@
size_t ipcObjectsCount() const;
void ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
size_t objectsCount, release_func relFunc);
- void rpcSetDataReference(const sp<RpcSession>& session, const uint8_t* data, size_t dataSize,
- release_func relFunc);
+ // Takes ownership even when an error is returned.
+ status_t rpcSetDataReference(
+ const sp<RpcSession>& session, const uint8_t* data, size_t dataSize,
+ const uint32_t* objectTable, size_t objectTableSize,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds,
+ release_func relFunc);
status_t finishWrite(size_t len);
void releaseObjects();
@@ -620,6 +624,7 @@
status_t restartWrite(size_t desired);
// Set the capacity to `desired`, truncating the Parcel if necessary.
status_t continueWrite(size_t desired);
+ status_t truncateRpcObjects(size_t newObjectsSize);
status_t writePointer(uintptr_t val);
status_t readPointer(uintptr_t *pArg) const;
uintptr_t readPointer() const;
@@ -1279,6 +1284,23 @@
// Should always be non-null.
const sp<RpcSession> mSession;
+
+ enum ObjectType : int32_t {
+ TYPE_BINDER_NULL = 0,
+ TYPE_BINDER = 1,
+ // FD to be passed via native transport (Trusty IPC or UNIX domain socket).
+ TYPE_NATIVE_FILE_DESCRIPTOR = 2,
+ };
+
+ // Sorted.
+ std::vector<uint32_t> mObjectPositions;
+
+ // File descriptors referenced by the parcel data. Should be indexed
+ // using the offsets in the parcel data. Don't assume the list is in the
+ // same order as `mObjectPositions`.
+ //
+ // Boxed to save space. Lazy allocated.
+ std::unique_ptr<std::vector<std::variant<base::unique_fd, base::borrowed_fd>>> mFds;
};
std::variant<KernelFields, RpcFields> mVariantFields;
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index dba8dd6..9318c27 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -18,6 +18,7 @@
#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
#include <binder/RpcSession.h>
+#include <binder/RpcThreads.h>
#include <binder/RpcTransport.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -114,6 +115,15 @@
void setProtocolVersion(uint32_t version);
/**
+ * Set the supported transports for sending and receiving file descriptors.
+ *
+ * Clients will propose a mode when connecting. If the mode is not in the
+ * provided list, the connection will be rejected.
+ */
+ void setSupportedFileDescriptorTransportModes(
+ const std::vector<RpcSession::FileDescriptorTransportMode>& modes);
+
+ /**
* The root object can be retrieved by any client, without any
* authentication. TODO(b/183988761)
*
@@ -193,18 +203,22 @@
const std::unique_ptr<RpcTransportCtx> mCtx;
size_t mMaxThreads = 1;
std::optional<uint32_t> mProtocolVersion;
+ // A mode is supported if the N'th bit is on, where N is the mode enum's value.
+ std::bitset<8> mSupportedFileDescriptorTransportModes = std::bitset<8>().set(
+ static_cast<size_t>(RpcSession::FileDescriptorTransportMode::NONE));
base::unique_fd mServer; // socket we are accepting sessions on
- std::mutex mLock; // for below
- std::unique_ptr<std::thread> mJoinThread;
+ RpcMutex mLock; // for below
+ std::unique_ptr<RpcMaybeThread> mJoinThread;
bool mJoinThreadRunning = false;
- std::map<std::thread::id, std::thread> mConnectingThreads;
+ std::map<RpcMaybeThread::id, RpcMaybeThread> mConnectingThreads;
+
sp<IBinder> mRootObject;
wp<IBinder> mRootObjectWeak;
std::function<sp<IBinder>(const void*, size_t)> mRootObjectFactory;
std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
std::unique_ptr<FdTrigger> mShutdownTrigger;
- std::condition_variable mShutdownCv;
+ RpcConditionVariable mShutdownCv;
};
} // namespace android
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 7d5d481..a2b28db 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -18,13 +18,13 @@
#include <android-base/threads.h>
#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
+#include <binder/RpcThreads.h>
#include <binder/RpcTransport.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <map>
#include <optional>
-#include <thread>
#include <vector>
namespace android {
@@ -95,6 +95,18 @@
[[nodiscard]] bool setProtocolVersion(uint32_t version);
std::optional<uint32_t> getProtocolVersion();
+ enum class FileDescriptorTransportMode : uint8_t {
+ NONE = 0,
+ // Send file descriptors via unix domain socket ancillary data.
+ UNIX = 1,
+ };
+
+ /**
+ * Set the transport for sending and receiving file descriptors.
+ */
+ void setFileDescriptorTransportMode(FileDescriptorTransportMode mode);
+ FileDescriptorTransportMode getFileDescriptorTransportMode();
+
/**
* This should be called once per thread, matching 'join' in the remote
* process.
@@ -206,10 +218,10 @@
public:
void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
void onSessionIncomingThreadEnded() override;
- void waitForShutdown(std::unique_lock<std::mutex>& lock, const sp<RpcSession>& session);
+ void waitForShutdown(RpcMutexUniqueLock& lock, const sp<RpcSession>& session);
private:
- std::condition_variable mCv;
+ RpcConditionVariable mCv;
};
friend WaitForShutdownListener;
@@ -232,7 +244,7 @@
//
// transfer ownership of thread (usually done while a lock is taken on the
// structure which originally owns the thread)
- void preJoinThreadOwnership(std::thread thread);
+ void preJoinThreadOwnership(RpcMaybeThread thread);
// pass FD to thread and read initial connection information
struct PreJoinSetupResult {
// Server connection object associated with this
@@ -314,7 +326,7 @@
// For a more complicated case, the client might itself open up a thread to
// serve calls to the server at all times (e.g. if it hosts a callback)
- wp<RpcServer> mForServer; // maybe null, for client sessions
+ wp<RpcServer> mForServer; // maybe null, for client sessions
sp<WaitForShutdownListener> mShutdownListener; // used for client sessions
wp<EventListener> mEventListener; // mForServer if server, mShutdownListener if client
@@ -328,13 +340,14 @@
std::unique_ptr<RpcState> mRpcBinderState;
- std::mutex mMutex; // for all below
+ RpcMutex mMutex; // for all below
size_t mMaxIncomingThreads = 0;
size_t mMaxOutgoingThreads = kDefaultMaxOutgoingThreads;
std::optional<uint32_t> mProtocolVersion;
+ FileDescriptorTransportMode mFileDescriptorTransportMode = FileDescriptorTransportMode::NONE;
- std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
+ RpcConditionVariable mAvailableConnectionCv; // for mWaitingThreads
struct ThreadState {
size_t mWaitingThreads = 0;
@@ -343,7 +356,7 @@
std::vector<sp<RpcConnection>> mOutgoing;
size_t mMaxIncoming = 0;
std::vector<sp<RpcConnection>> mIncoming;
- std::map<std::thread::id, std::thread> mThreads;
+ std::map<RpcMaybeThread::id, RpcMaybeThread> mThreads;
} mConnections;
};
diff --git a/libs/binder/include/binder/RpcThreads.h b/libs/binder/include/binder/RpcThreads.h
new file mode 100644
index 0000000..8abf04e
--- /dev/null
+++ b/libs/binder/include/binder/RpcThreads.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <pthread.h>
+
+#include <android-base/threads.h>
+
+#include <functional>
+#include <memory>
+#include <thread>
+
+namespace android {
+
+#ifdef BINDER_RPC_SINGLE_THREADED
+class RpcMutex {
+public:
+ void lock() {}
+ void unlock() {}
+};
+
+class RpcMutexUniqueLock {
+public:
+ RpcMutexUniqueLock(RpcMutex&) {}
+ void unlock() {}
+};
+
+class RpcMutexLockGuard {
+public:
+ RpcMutexLockGuard(RpcMutex&) {}
+};
+
+class RpcConditionVariable {
+public:
+ void notify_one() {}
+ void notify_all() {}
+
+ void wait(RpcMutexUniqueLock&) {}
+
+ template <typename Predicate>
+ void wait(RpcMutexUniqueLock&, Predicate stop_waiting) {
+ LOG_ALWAYS_FATAL_IF(!stop_waiting(), "RpcConditionVariable::wait condition not met");
+ }
+
+ template <typename Duration>
+ std::cv_status wait_for(RpcMutexUniqueLock&, const Duration&) {
+ return std::cv_status::no_timeout;
+ }
+
+ template <typename Duration, typename Predicate>
+ bool wait_for(RpcMutexUniqueLock&, const Duration&, Predicate stop_waiting) {
+ return stop_waiting();
+ }
+};
+
+class RpcMaybeThread {
+public:
+ RpcMaybeThread() = default;
+
+ template <typename Function, typename... Args>
+ RpcMaybeThread(Function&& f, Args&&... args) {
+ // std::function requires a copy-constructible closure,
+ // so we need to wrap both the function and its arguments
+ // in a shared pointer that std::function can copy internally
+ struct Vars {
+ std::decay_t<Function> f;
+ std::tuple<std::decay_t<Args>...> args;
+
+ explicit Vars(Function&& f, Args&&... args)
+ : f(std::move(f)), args(std::move(args)...) {}
+ };
+ auto vars = std::make_shared<Vars>(std::forward<Function>(f), std::forward<Args>(args)...);
+ mFunc = [vars]() { std::apply(std::move(vars->f), std::move(vars->args)); };
+ }
+
+ void join() {
+ if (mFunc) {
+ // Move mFunc into a temporary so we can clear mFunc before
+ // executing the callback. This avoids infinite recursion if
+ // the callee then calls join() again directly or indirectly.
+ decltype(mFunc) func = nullptr;
+ mFunc.swap(func);
+ func();
+ }
+ }
+ void detach() { join(); }
+
+ class id {
+ public:
+ bool operator==(const id&) const { return true; }
+ bool operator!=(const id&) const { return false; }
+ bool operator<(const id&) const { return false; }
+ bool operator<=(const id&) const { return true; }
+ bool operator>(const id&) const { return false; }
+ bool operator>=(const id&) const { return true; }
+ };
+
+ id get_id() const { return id(); }
+
+private:
+ std::function<void(void)> mFunc;
+};
+
+namespace rpc_this_thread {
+static inline RpcMaybeThread::id get_id() {
+ return RpcMaybeThread::id();
+}
+} // namespace rpc_this_thread
+
+static inline uint64_t rpcGetThreadId() {
+ return 0;
+}
+
+static inline void rpcJoinIfSingleThreaded(RpcMaybeThread& t) {
+ t.join();
+}
+#else // BINDER_RPC_SINGLE_THREADED
+using RpcMutex = std::mutex;
+using RpcMutexUniqueLock = std::unique_lock<std::mutex>;
+using RpcMutexLockGuard = std::lock_guard<std::mutex>;
+using RpcConditionVariable = std::condition_variable;
+using RpcMaybeThread = std::thread;
+namespace rpc_this_thread = std::this_thread;
+
+static inline uint64_t rpcGetThreadId() {
+ return base::GetThreadId();
+}
+
+static inline void rpcJoinIfSingleThreaded(RpcMaybeThread&) {}
+#endif // BINDER_RPC_SINGLE_THREADED
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index ee4b548..5197ef9 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -22,6 +22,8 @@
#include <memory>
#include <optional>
#include <string>
+#include <variant>
+#include <vector>
#include <android-base/function_ref.h>
#include <android-base/unique_fd.h>
@@ -61,16 +63,23 @@
* to read/write data. If this returns an error, that error is returned from
* this function.
*
+ * ancillaryFds - FDs to be sent via UNIX domain dockets or Trusty IPC. When
+ * reading, if `ancillaryFds` is null, any received FDs will be silently
+ * dropped and closed (by the OS). Appended values will always be unique_fd,
+ * the variant type is used to avoid extra copies elsewhere.
+ *
* Return:
* OK - succeeded in completely processing 'size'
* error - interrupted (failure or trigger)
*/
[[nodiscard]] virtual status_t interruptableWriteFully(
FdTrigger *fdTrigger, iovec *iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>> &altPoll) = 0;
+ const std::optional<android::base::function_ref<status_t()>> &altPoll,
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>> *ancillaryFds) = 0;
[[nodiscard]] virtual status_t interruptableReadFully(
FdTrigger *fdTrigger, iovec *iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>> &altPoll) = 0;
+ const std::optional<android::base::function_ref<status_t()>> &altPoll,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>> *ancillaryFds) = 0;
protected:
RpcTransport() = default;
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index 2deea82..b15a225 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -67,4 +67,8 @@
void scheduleShutdown();
void useKernelBinderCallingId();
+
+ ParcelFileDescriptor echoAsFile(@utf8InCpp String content);
+
+ ParcelFileDescriptor concatFiles(in List<ParcelFileDescriptor> files);
}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 141fa38..3766278 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -23,6 +23,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
#include <android/binder_auto_utils.h>
#include <android/binder_libbinder.h>
#include <binder/Binder.h>
@@ -47,12 +48,14 @@
#include <poll.h>
#include <sys/prctl.h>
+#include <sys/socket.h>
#include <unistd.h>
#include "../FdTrigger.h"
#include "../RpcSocketAddress.h" // for testing preconnected clients
#include "../RpcState.h" // for debugging
#include "../vm_sockets.h" // for VMADDR_*
+#include "utils/Errors.h"
using namespace std::chrono_literals;
using namespace std::placeholders;
@@ -92,6 +95,21 @@
}
}
+// Create an FD that returns `contents` when read.
+static base::unique_fd mockFileDescriptor(std::string contents) {
+ android::base::unique_fd readFd, writeFd;
+ CHECK(android::base::Pipe(&readFd, &writeFd)) << strerror(errno);
+ std::thread([writeFd = std::move(writeFd), contents = std::move(contents)]() {
+ signal(SIGPIPE, SIG_IGN); // ignore possible SIGPIPE from the write
+ if (!WriteStringToFd(contents, writeFd)) {
+ int savedErrno = errno;
+ EXPECT_EQ(EPIPE, savedErrno)
+ << "mockFileDescriptor write failed: " << strerror(savedErrno);
+ }
+ }).detach();
+ return readFd;
+}
+
TEST(BinderRpcParcel, EntireParcelFormatted) {
Parcel p;
p.writeInt32(3);
@@ -328,9 +346,36 @@
(void)IPCThreadState::self()->getCallingPid();
return Status::ok();
}
+
+ Status echoAsFile(const std::string& content, android::os::ParcelFileDescriptor* out) override {
+ out->reset(mockFileDescriptor(content));
+ return Status::ok();
+ }
+
+ Status concatFiles(const std::vector<android::os::ParcelFileDescriptor>& files,
+ android::os::ParcelFileDescriptor* out) override {
+ std::string acc;
+ for (const auto& file : files) {
+ std::string result;
+ CHECK(android::base::ReadFdToString(file.get(), &result));
+ acc.append(result);
+ }
+ out->reset(mockFileDescriptor(acc));
+ return Status::ok();
+ }
};
sp<IBinder> MyBinderRpcTest::mHeldBinder;
+static std::string WaitStatusToString(int wstatus) {
+ if (WIFEXITED(wstatus)) {
+ return base::StringPrintf("exit status %d", WEXITSTATUS(wstatus));
+ }
+ if (WIFSIGNALED(wstatus)) {
+ return base::StringPrintf("term signal %d", WTERMSIG(wstatus));
+ }
+ return base::StringPrintf("unexpected state %d", wstatus);
+}
+
class Process {
public:
Process(Process&&) = default;
@@ -351,13 +396,28 @@
}
~Process() {
if (mPid != 0) {
- waitpid(mPid, nullptr, 0);
+ int wstatus;
+ waitpid(mPid, &wstatus, 0);
+ if (mCustomExitStatusCheck) {
+ mCustomExitStatusCheck(wstatus);
+ } else {
+ EXPECT_TRUE(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0)
+ << "server process failed: " << WaitStatusToString(wstatus);
+ }
}
}
android::base::borrowed_fd readEnd() { return mReadEnd; }
android::base::borrowed_fd writeEnd() { return mWriteEnd; }
+ void setCustomExitStatusCheck(std::function<void(int wstatus)> f) {
+ mCustomExitStatusCheck = std::move(f);
+ }
+
+ // Kill the process. Avoid if possible. Shutdown gracefully via an RPC instead.
+ void terminate() { kill(mPid, SIGTERM); }
+
private:
+ std::function<void(int wstatus)> mCustomExitStatusCheck;
pid_t mPid = 0;
android::base::unique_fd mReadEnd;
android::base::unique_fd mWriteEnd;
@@ -425,10 +485,10 @@
BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
~BinderRpcTestProcessSession() {
- EXPECT_NE(nullptr, rootIface);
- if (rootIface == nullptr) return;
-
if (!expectAlreadyShutdown) {
+ EXPECT_NE(nullptr, rootIface);
+ if (rootIface == nullptr) return;
+
std::vector<int32_t> remoteCounts;
// calling over any sessions counts across all sessions
EXPECT_OK(rootIface->countBinders(&remoteCounts));
@@ -494,8 +554,28 @@
size_t numSessions = 1;
size_t numIncomingConnections = 0;
size_t numOutgoingConnections = SIZE_MAX;
+ RpcSession::FileDescriptorTransportMode clientFileDescriptorTransportMode =
+ RpcSession::FileDescriptorTransportMode::NONE;
+ std::vector<RpcSession::FileDescriptorTransportMode>
+ serverSupportedFileDescriptorTransportModes = {
+ RpcSession::FileDescriptorTransportMode::NONE};
+
+ // If true, connection failures will result in `ProcessSession::sessions` being empty
+ // instead of a fatal error.
+ bool allowConnectFailure = false;
};
+ SocketType socketType() const { return std::get<0>(GetParam()); }
+ RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); }
+ uint32_t clientVersion() const { return std::get<2>(GetParam()); }
+ uint32_t serverVersion() const { return std::get<3>(GetParam()); }
+
+ // Whether the test params support sending FDs in parcels.
+ bool supportsFdTransport() const {
+ return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
+ (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX);
+ }
+
static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
auto [type, security, clientVersion, serverVersion] = info.param;
return PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
@@ -555,6 +635,8 @@
server->setProtocolVersion(serverVersion);
server->setMaxThreads(options.numThreads);
+ server->setSupportedFileDescriptorTransportModes(
+ options.serverSupportedFileDescriptorTransportModes);
unsigned int outPort = 0;
@@ -632,6 +714,7 @@
CHECK(session->setProtocolVersion(clientVersion));
session->setMaxIncomingThreads(options.numIncomingConnections);
session->setMaxOutgoingThreads(options.numOutgoingConnections);
+ session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
switch (socketType) {
case SocketType::PRECONNECTED:
@@ -651,6 +734,10 @@
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
+ if (options.allowConnectFailure && status != OK) {
+ ret.sessions.clear();
+ break;
+ }
CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
ret.sessions.push_back({session, session->getRootObject()});
}
@@ -699,7 +786,7 @@
}),
};
- ret.rootBinder = ret.proc.sessions.at(0).root;
+ ret.rootBinder = ret.proc.sessions.empty() ? nullptr : ret.proc.sessions.at(0).root;
ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
return ret;
@@ -950,7 +1037,13 @@
}
TEST_P(BinderRpc, NestedTransactions) {
- auto proc = createRpcTestSocketServerProcess({});
+ auto proc = createRpcTestSocketServerProcess({
+ // Enable FD support because it uses more stack space and so represents
+ // something closer to a worst case scenario.
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ });
auto nastyNester = sp<MyBinderRpcTest>::make();
EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
@@ -1297,6 +1390,12 @@
// need to manually shut it down
EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+ proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+ // Flaky. Sometimes gets SIGABRT.
+ EXPECT_TRUE((WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) ||
+ (WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT))
+ << "server process failed: " << WaitStatusToString(wstatus);
+ });
proc.expectAlreadyShutdown = true;
}
}
@@ -1326,6 +1425,10 @@
EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
<< "Do death cleanup: " << doDeathCleanup;
+ proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+ EXPECT_TRUE(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 1)
+ << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+ });
proc.expectAlreadyShutdown = true;
}
}
@@ -1349,9 +1452,150 @@
// second time! we catch the error :)
EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
+ proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+ EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT)
+ << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+ });
proc.expectAlreadyShutdown = true;
}
+TEST_P(BinderRpc, FileDescriptorTransportRejectNone) {
+ auto proc = createRpcTestSocketServerProcess({
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::NONE,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ .allowConnectFailure = true,
+ });
+ EXPECT_TRUE(proc.proc.sessions.empty()) << "session connections should have failed";
+ proc.proc.host.terminate();
+ proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+ EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
+ << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+ });
+ proc.expectAlreadyShutdown = true;
+}
+
+TEST_P(BinderRpc, FileDescriptorTransportRejectUnix) {
+ auto proc = createRpcTestSocketServerProcess({
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::NONE},
+ .allowConnectFailure = true,
+ });
+ EXPECT_TRUE(proc.proc.sessions.empty()) << "session connections should have failed";
+ proc.proc.host.terminate();
+ proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+ EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
+ << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+ });
+ proc.expectAlreadyShutdown = true;
+}
+
+TEST_P(BinderRpc, FileDescriptorTransportOptionalUnix) {
+ auto proc = createRpcTestSocketServerProcess({
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::NONE,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::NONE,
+ RpcSession::FileDescriptorTransportMode::UNIX},
+ });
+
+ android::os::ParcelFileDescriptor out;
+ auto status = proc.rootIface->echoAsFile("hello", &out);
+ EXPECT_EQ(status.transactionError(), FDS_NOT_ALLOWED) << status;
+}
+
+TEST_P(BinderRpc, ReceiveFile) {
+ auto proc = createRpcTestSocketServerProcess({
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ });
+
+ android::os::ParcelFileDescriptor out;
+ auto status = proc.rootIface->echoAsFile("hello", &out);
+ if (!supportsFdTransport()) {
+ EXPECT_EQ(status.transactionError(), BAD_VALUE) << status;
+ return;
+ }
+ ASSERT_TRUE(status.isOk()) << status;
+
+ std::string result;
+ CHECK(android::base::ReadFdToString(out.get(), &result));
+ EXPECT_EQ(result, "hello");
+}
+
+TEST_P(BinderRpc, SendFiles) {
+ auto proc = createRpcTestSocketServerProcess({
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ });
+
+ std::vector<android::os::ParcelFileDescriptor> files;
+ files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("123")));
+ files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("a")));
+ files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("b")));
+ files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("cd")));
+
+ android::os::ParcelFileDescriptor out;
+ auto status = proc.rootIface->concatFiles(files, &out);
+ if (!supportsFdTransport()) {
+ EXPECT_EQ(status.transactionError(), BAD_VALUE) << status;
+ return;
+ }
+ ASSERT_TRUE(status.isOk()) << status;
+
+ std::string result;
+ CHECK(android::base::ReadFdToString(out.get(), &result));
+ EXPECT_EQ(result, "123abcd");
+}
+
+TEST_P(BinderRpc, SendMaxFiles) {
+ if (!supportsFdTransport()) {
+ GTEST_SKIP() << "Would fail trivially (which is tested by BinderRpc::SendFiles)";
+ }
+
+ auto proc = createRpcTestSocketServerProcess({
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ });
+
+ std::vector<android::os::ParcelFileDescriptor> files;
+ for (int i = 0; i < 253; i++) {
+ files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("a")));
+ }
+
+ android::os::ParcelFileDescriptor out;
+ auto status = proc.rootIface->concatFiles(files, &out);
+ ASSERT_TRUE(status.isOk()) << status;
+
+ std::string result;
+ CHECK(android::base::ReadFdToString(out.get(), &result));
+ EXPECT_EQ(result, std::string(253, 'a'));
+}
+
+TEST_P(BinderRpc, SendTooManyFiles) {
+ if (!supportsFdTransport()) {
+ GTEST_SKIP() << "Would fail trivially (which is tested by BinderRpc::SendFiles)";
+ }
+
+ auto proc = createRpcTestSocketServerProcess({
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ });
+
+ std::vector<android::os::ParcelFileDescriptor> files;
+ for (int i = 0; i < 254; i++) {
+ files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("a")));
+ }
+
+ android::os::ParcelFileDescriptor out;
+ auto status = proc.rootIface->concatFiles(files, &out);
+ EXPECT_EQ(status.transactionError(), BAD_VALUE) << status;
+}
+
TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
auto proc = createRpcTestSocketServerProcess({});
@@ -1409,20 +1653,90 @@
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(RpcTransportCtxFactoryRaw::make());
- 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(RpcTransportCtxFactoryRaw::make());
- status_t status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
- while (!server->shutdown()) usleep(10000);
- ALOGE("Detected vsock loopback supported: %s", statusToString(status).c_str());
- return status == OK;
+ android::base::unique_fd serverFd(
+ TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
+ LOG_ALWAYS_FATAL_IF(serverFd == -1, "Could not create socket: %s", strerror(errno));
+
+ sockaddr_vm serverAddr{
+ .svm_family = AF_VSOCK,
+ .svm_port = vsockPort,
+ .svm_cid = VMADDR_CID_ANY,
+ };
+ int ret = TEMP_FAILURE_RETRY(
+ bind(serverFd.get(), reinterpret_cast<sockaddr*>(&serverAddr), sizeof(serverAddr)));
+ LOG_ALWAYS_FATAL_IF(0 != ret, "Could not bind socket to port %u: %s", vsockPort,
+ strerror(errno));
+
+ ret = TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/));
+ LOG_ALWAYS_FATAL_IF(0 != ret, "Could not listen socket on port %u: %s", vsockPort,
+ strerror(errno));
+
+ // Try to connect to the server using the VMADDR_CID_LOCAL cid
+ // to see if the kernel supports it. It's safe to use a blocking
+ // connect because vsock sockets have a 2 second connection timeout,
+ // and they return ETIMEDOUT after that.
+ android::base::unique_fd connectFd(
+ TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
+ LOG_ALWAYS_FATAL_IF(connectFd == -1, "Could not create socket for port %u: %s", vsockPort,
+ strerror(errno));
+
+ bool success = false;
+ sockaddr_vm connectAddr{
+ .svm_family = AF_VSOCK,
+ .svm_port = vsockPort,
+ .svm_cid = VMADDR_CID_LOCAL,
+ };
+ ret = TEMP_FAILURE_RETRY(connect(connectFd.get(), reinterpret_cast<sockaddr*>(&connectAddr),
+ sizeof(connectAddr)));
+ if (ret != 0 && (errno == EAGAIN || errno == EINPROGRESS)) {
+ android::base::unique_fd acceptFd;
+ while (true) {
+ pollfd pfd[]{
+ {.fd = serverFd.get(), .events = POLLIN, .revents = 0},
+ {.fd = connectFd.get(), .events = POLLOUT, .revents = 0},
+ };
+ ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
+ LOG_ALWAYS_FATAL_IF(ret < 0, "Error polling: %s", strerror(errno));
+
+ if (pfd[0].revents & POLLIN) {
+ sockaddr_vm acceptAddr;
+ socklen_t acceptAddrLen = sizeof(acceptAddr);
+ ret = TEMP_FAILURE_RETRY(accept4(serverFd.get(),
+ reinterpret_cast<sockaddr*>(&acceptAddr),
+ &acceptAddrLen, SOCK_CLOEXEC));
+ LOG_ALWAYS_FATAL_IF(ret < 0, "Could not accept4 socket: %s", strerror(errno));
+ LOG_ALWAYS_FATAL_IF(acceptAddrLen != static_cast<socklen_t>(sizeof(acceptAddr)),
+ "Truncated address");
+
+ // Store the fd in acceptFd so we keep the connection alive
+ // while polling connectFd
+ acceptFd.reset(ret);
+ }
+
+ if (pfd[1].revents & POLLOUT) {
+ // Connect either succeeded or timed out
+ int connectErrno;
+ socklen_t connectErrnoLen = sizeof(connectErrno);
+ int ret = getsockopt(connectFd.get(), SOL_SOCKET, SO_ERROR, &connectErrno,
+ &connectErrnoLen);
+ LOG_ALWAYS_FATAL_IF(ret == -1,
+ "Could not getsockopt() after connect() "
+ "on non-blocking socket: %s.",
+ strerror(errno));
+
+ // We're done, this is all we wanted
+ success = connectErrno == 0;
+ break;
+ }
+ }
+ } else {
+ success = ret == 0;
+ }
+
+ ALOGE("Detected vsock loopback supported: %s", success ? "yes" : "no");
+
+ return success;
}
static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
@@ -1722,7 +2036,7 @@
std::string message(kMessage);
iovec messageIov{message.data(), message.size()};
auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1,
- std::nullopt);
+ std::nullopt, nullptr);
if (status != OK) return AssertionFailure() << statusToString(status);
return AssertionSuccess();
}
@@ -1757,7 +2071,7 @@
iovec readMessageIov{readMessage.data(), readMessage.size()};
status_t readStatus =
mClientTransport->interruptableReadFully(mFdTrigger.get(), &readMessageIov, 1,
- std::nullopt);
+ std::nullopt, nullptr);
if (readStatus != OK) {
return AssertionFailure() << statusToString(readStatus);
}
@@ -1965,8 +2279,8 @@
auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) {
std::string message(RpcTransportTestUtils::kMessage);
iovec messageIov{message.data(), message.size()};
- auto status =
- serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, std::nullopt);
+ auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1,
+ std::nullopt, nullptr);
if (status != OK) return AssertionFailure() << statusToString(status);
{
@@ -1977,7 +2291,8 @@
}
iovec msg2Iov{msg2.data(), msg2.size()};
- status = serverTransport->interruptableWriteFully(fdTrigger, &msg2Iov, 1, std::nullopt);
+ status = serverTransport->interruptableWriteFully(fdTrigger, &msg2Iov, 1, std::nullopt,
+ nullptr);
if (status != DEAD_OBJECT)
return AssertionFailure() << "When FdTrigger is shut down, interruptableWriteFully "
"should return DEAD_OBJECT, but it is "
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 0f1a02a..a6585c5 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -85,7 +85,20 @@
/* list of hal interface to dump containing process during native dumps */
static const std::vector<std::string> aidl_interfaces_to_dump {
+ "android.hardware.automotive.audiocontrol.IAudioControl",
+ "android.hardware.automotive.evs.IEvsEnumerator",
+ "android.hardware.biometrics.face.IBiometricsFace",
+ "android.hardware.biometrics.fingerprint.IBiometricsFingerprint",
"android.hardware.camera.provider.ICameraProvider",
+ "android.hardware.drm.IDrmFactory",
+ "android.hardware.graphics.allocator.IAllocator",
+ "android.hardware.graphics.composer3.IComposer",
+ "android.hardware.health.IHealth",
+ "android.hardware.input.processor.IInputProcessor",
+ "android.hardware.neuralnetworks.IDevice",
+ "android.hardware.power.IPower",
+ "android.hardware.power.stats.IPowerStats",
+ "android.hardware.sensors.ISensors",
};
/* list of extra hal interfaces to dump containing process during native dumps */
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index bf848af..06ecd25 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -31,7 +31,7 @@
"vr_flinger.cpp",
]
-includeFiles = [ "include" ]
+includeFiles = ["include"]
staticLibraries = [
"libdisplay",
@@ -83,8 +83,6 @@
cc_library_static {
srcs: sourceFiles,
export_include_dirs: includeFiles,
-
- clang: true,
cflags: [
"-DLOG_TAG=\"vr_flinger\"",
"-DTRACE=0",
diff --git a/services/gpuservice/tests/unittests/GpuStatsTest.cpp b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
index 3c7644f..7ea2288 100644
--- a/services/gpuservice/tests/unittests/GpuStatsTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
@@ -76,6 +76,12 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ // This is required for test due to GpuStats instance spawns binder transactions
+ // in its destructor. After the gtest destructor test exits immidiatelly.
+ // It results in binder thread not able to process above binder transactions and memory leak
+ // occures. Binder thread needs time to process callbacks transactions.
+ // It leads to GpuStats instance destructor needs to be called in advance.
+ mGpuStats.reset(nullptr);
// performs all pending callbacks until all data has been consumed
// gives time to process binder transactions by thread pool
looper->pollAll(1000);
diff --git a/services/inputflinger/OWNERS b/services/inputflinger/OWNERS
index 82c6ee1..c88bfe9 100644
--- a/services/inputflinger/OWNERS
+++ b/services/inputflinger/OWNERS
@@ -1,3 +1 @@
-lzye@google.com
-michaelwr@google.com
-svv@google.com
+include platform/frameworks/base:/INPUT_OWNERS
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index ac5f6b6..17bbff8 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -813,6 +813,10 @@
mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
}
} else {
+ if (mPointerController != nullptr && mDeviceMode == DeviceMode::DIRECT &&
+ !mConfig.showTouches) {
+ mPointerController->clearSpots();
+ }
mPointerController.reset();
}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 969c8ba..0d5d06a 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -192,7 +192,7 @@
mSpotsByDisplay[displayId] = newSpots;
}
- void clearSpots() override {}
+ void clearSpots() override { mSpotsByDisplay.clear(); }
std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay;
};
@@ -7959,7 +7959,8 @@
// Default device will reconfigure above, need additional reconfiguration for another device.
device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO |
+ InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
// Two fingers down at default display.
int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500;
@@ -7986,6 +7987,13 @@
iter = fakePointerController->getSpots().find(SECONDARY_DISPLAY_ID);
ASSERT_TRUE(iter != fakePointerController->getSpots().end());
ASSERT_EQ(size_t(2), iter->second.size());
+
+ // Disable the show touches configuration and ensure the spots are cleared.
+ mFakePolicy->setShowTouches(false);
+ device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
+
+ ASSERT_TRUE(fakePointerController->getSpots().empty());
}
TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) {
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index 6916764..1834f2a 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -94,7 +94,8 @@
EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
-TEST_F(OneShotTimerTest, resetBackToBackTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_resetBackToBackTest) {
fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),