Merge "Point directly to generated c sysprop_library" into tm-d1-dev-plus-aosp
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 942a17e..f759674 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "dumpstate"
+#define ATRACE_TAG ATRACE_TAG_ALWAYS
#include <dirent.h>
#include <errno.h>
@@ -76,6 +77,7 @@
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
+#include <cutils/trace.h>
#include <debuggerd/client.h>
#include <dumpsys.h>
#include <dumputils/dump_utils.h>
@@ -3098,7 +3100,9 @@
TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
// Zip the (now complete) .tmp file within the internal directory.
+ ATRACE_BEGIN("FinalizeFile");
FinalizeFile();
+ ATRACE_END();
// Share the final file with the caller if the user has consented or Shell is the caller.
Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
@@ -3409,6 +3413,9 @@
duration_fd_(duration_fd) {
if (!title_.empty()) {
started_ = Nanotime();
+ if (title_.find("SHOW MAP") == std::string::npos) {
+ ATRACE_ASYNC_BEGIN(title_.c_str(), 0);
+ }
}
}
@@ -3423,6 +3430,9 @@
dprintf(duration_fd_, "------ %.3fs was the duration of '%s' ------\n",
elapsed, title_.c_str());
}
+ if (title_.find("SHOW MAP") == std::string::npos) {
+ ATRACE_ASYNC_END(title_.c_str(), 0);
+ }
}
}
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 45aeab6..4d9b710 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -1184,8 +1184,8 @@
int wait_child_with_timeout(pid_t pid, int timeout_ms) {
int pidfd = pidfd_open(pid, /*flags=*/0);
if (pidfd < 0) {
- PLOG(ERROR) << "pidfd_open failed for pid " << pid;
- kill(pid, SIGKILL);
+ PLOG(ERROR) << "pidfd_open failed for pid " << pid
+ << ", waiting for child process without timeout";
return wait_child(pid);
}
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 2fb9c2b..1d458b7 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -121,6 +121,8 @@
const char* driver = argc == 2 ? argv[1] : "/dev/binder";
+ LOG(INFO) << "Starting sm instance on " << driver;
+
sp<ProcessState> ps = ProcessState::initWithDriver(driver);
ps->setThreadPoolMaxThreadCount(0);
ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 3becdd0..441a4a8 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -70,21 +70,9 @@
],
}
-cc_library {
- name: "libbinder",
-
- version_script: "libbinder.map",
-
- // for vndbinder
- vendor_available: true,
- vndk: {
- enabled: true,
- },
- recovery_available: true,
- double_loadable: true,
+cc_defaults {
+ name: "libbinder_defaults",
host_supported: true,
- // TODO(b/153609531): remove when no longer needed.
- native_bridge_supported: true,
// TODO(b/31559095): get headers from bionic on host
include_dirs: [
@@ -92,73 +80,32 @@
"bionic/libc/kernel/uapi/",
],
- // libbinder does not offer a stable wire protocol.
- // if a second copy of it is installed, then it may break after security
- // or dessert updates. Instead, apex users should use libbinder_ndk.
- apex_available: [
- "//apex_available:platform",
- ],
-
srcs: [
"Binder.cpp",
"BpBinder.cpp",
- "BufferedTextOutput.cpp",
"Debug.cpp",
"FdTrigger.cpp",
"IInterface.cpp",
- "IMemory.cpp",
- "IPCThreadState.cpp",
"IResultReceiver.cpp",
- "IServiceManager.cpp",
- "IShellCallback.cpp",
- "LazyServiceRegistrar.cpp",
- "MemoryBase.cpp",
- "MemoryDealer.cpp",
- "MemoryHeapBase.cpp",
+ "OS.cpp",
"Parcel.cpp",
- "ParcelableHolder.cpp",
"ParcelFileDescriptor.cpp",
- "PersistableBundle.cpp",
- "ProcessState.cpp",
"RpcSession.cpp",
"RpcServer.cpp",
"RpcState.cpp",
"RpcTransportRaw.cpp",
- "Static.cpp",
"Stability.cpp",
"Status.cpp",
"TextOutput.cpp",
"Utils.cpp",
- ":libbinder_aidl",
- ":libbinder_device_interface_sources",
],
target: {
- android: {
- // NOT static to keep the wire protocol unfrozen
- static: {
- enabled: false,
- },
- },
- vendor: {
- exclude_srcs: [
- ":libbinder_device_interface_sources",
- ],
- },
- darwin: {
- enabled: false,
- },
host: {
srcs: [
- "ServiceManagerHost.cpp",
"UtilsHost.cpp",
],
},
- recovery: {
- exclude_header_libs: [
- "libandroid_runtime_vm_headers",
- ],
- },
},
aidl: {
@@ -166,7 +113,6 @@
},
cflags: [
- "-Wall",
"-Wextra",
"-Wextra-semi",
"-Werror",
@@ -229,6 +175,89 @@
"performance*",
"portability*",
],
+}
+
+cc_defaults {
+ name: "libbinder_kernel_defaults",
+ srcs: [
+ "BufferedTextOutput.cpp",
+ "IPCThreadState.cpp",
+ "IServiceManager.cpp",
+ "ProcessState.cpp",
+ "Static.cpp",
+ ":libbinder_aidl",
+ ":libbinder_device_interface_sources",
+ ],
+ target: {
+ vendor: {
+ exclude_srcs: [
+ ":libbinder_device_interface_sources",
+ ],
+ },
+ host: {
+ srcs: [
+ "ServiceManagerHost.cpp",
+ ],
+ },
+ },
+ cflags: [
+ "-DBINDER_WITH_KERNEL_IPC",
+ ],
+}
+
+cc_library {
+ name: "libbinder",
+ defaults: [
+ "libbinder_defaults",
+ "libbinder_kernel_defaults",
+ ],
+
+ version_script: "libbinder.map",
+
+ // for vndbinder
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ recovery_available: true,
+ double_loadable: true,
+ // TODO(b/153609531): remove when no longer needed.
+ native_bridge_supported: true,
+
+ // libbinder does not offer a stable wire protocol.
+ // if a second copy of it is installed, then it may break after security
+ // or dessert updates. Instead, apex users should use libbinder_ndk.
+ apex_available: [
+ "//apex_available:platform",
+ ],
+
+ srcs: [
+ "IMemory.cpp",
+ "IShellCallback.cpp",
+ "LazyServiceRegistrar.cpp",
+ "MemoryBase.cpp",
+ "MemoryDealer.cpp",
+ "MemoryHeapBase.cpp",
+ "ParcelableHolder.cpp",
+ "PersistableBundle.cpp",
+ ],
+
+ target: {
+ android: {
+ // NOT static to keep the wire protocol unfrozen
+ static: {
+ enabled: false,
+ },
+ },
+ darwin: {
+ enabled: false,
+ },
+ recovery: {
+ exclude_header_libs: [
+ "libandroid_runtime_vm_headers",
+ ],
+ },
+ },
afdo: true,
@@ -237,6 +266,39 @@
},
}
+cc_library_static {
+ name: "libbinder_rpc_no_kernel",
+ defaults: ["libbinder_defaults"],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
+cc_library_static {
+ name: "libbinder_rpc_single_threaded",
+ defaults: [
+ "libbinder_defaults",
+ "libbinder_kernel_defaults",
+ ],
+ cflags: [
+ "-DBINDER_RPC_SINGLE_THREADED",
+ ],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
+cc_library_static {
+ name: "libbinder_rpc_single_threaded_no_kernel",
+ defaults: ["libbinder_defaults"],
+ cflags: [
+ "-DBINDER_RPC_SINGLE_THREADED",
+ ],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
cc_defaults {
name: "libbinder_tls_shared_deps",
shared_libs: [
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index e2db1a3..532bacb 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);
@@ -635,13 +648,14 @@
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
args.add(data.readString16());
}
- sp<IShellCallback> shellCallback = IShellCallback::asInterface(
- data.readStrongBinder());
+ sp<IBinder> shellCallbackBinder = data.readStrongBinder();
sp<IResultReceiver> resultReceiver = IResultReceiver::asInterface(
data.readStrongBinder());
// XXX can't add virtuals until binaries are updated.
- //return shellCommand(in, out, err, args, resultReceiver);
+ // sp<IShellCallback> shellCallback = IShellCallback::asInterface(
+ // shellCallbackBinder);
+ // return shellCommand(in, out, err, args, resultReceiver);
(void)in;
(void)out;
(void)err;
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/OS.cpp b/libs/binder/OS.cpp
new file mode 100644
index 0000000..6eb7272
--- /dev/null
+++ b/libs/binder/OS.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#include "OS.h"
+
+#include <android-base/file.h>
+#include <string.h>
+
+using android::base::ErrnoError;
+using android::base::Result;
+
+namespace android {
+
+Result<void> setNonBlocking(android::base::borrowed_fd fd) {
+ int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL));
+ if (flags == -1) {
+ return ErrnoError() << "Could not get flags for fd";
+ }
+ if (int ret = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_SETFL, flags | O_NONBLOCK)); ret == -1) {
+ return ErrnoError() << "Could not set non-blocking flag for fd";
+ }
+ return {};
+}
+
+status_t getRandomBytes(uint8_t* data, size_t size) {
+ int ret = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+ if (ret == -1) {
+ return -errno;
+ }
+
+ base::unique_fd fd(ret);
+ if (!base::ReadFully(fd, data, size)) {
+ return -errno;
+ }
+ return OK;
+}
+
+} // namespace android
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
new file mode 100644
index 0000000..e802e9c
--- /dev/null
+++ b/libs/binder/OS.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.
+ */
+#pragma once
+
+#include <stddef.h>
+#include <cstdint>
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);
+
+status_t getRandomBytes(uint8_t* data, size_t size);
+
+} // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 0354382..537527e 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>
@@ -52,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__)
// ---------------------------------------------------------------------------
@@ -100,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) {
@@ -152,6 +167,7 @@
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);
@@ -183,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;
@@ -210,6 +228,7 @@
return finishFlattenBinder(binder);
}
+#ifdef BINDER_WITH_KERNEL_IPC
flat_binder_object obj;
int schedBits = 0;
@@ -266,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
@@ -295,6 +318,7 @@
return finishUnflattenBinder(binder, out);
}
+#ifdef BINDER_WITH_KERNEL_IPC
const flat_binder_object* flat = readObject(false);
if (flat) {
@@ -312,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
}
// ---------------------------------------------------------------------------
@@ -476,6 +504,7 @@
err = NO_ERROR;
if (auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
auto* otherKernelFields = parcel->maybeKernelFields();
LOG_ALWAYS_FATAL_IF(otherKernelFields == nullptr);
@@ -535,6 +564,10 @@
}
}
}
+#else
+ LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+ return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
} else {
auto* rpcFields = maybeRpcFields();
LOG_ALWAYS_FATAL_IF(rpcFields == nullptr);
@@ -658,6 +691,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;
@@ -677,6 +711,8 @@
}
setDataPosition(initPosition);
+#endif // BINDER_WITH_KERNEL_IPC
+
return ret;
}
@@ -684,6 +720,7 @@
std::vector<int> 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];
@@ -698,6 +735,9 @@
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));
@@ -719,6 +759,7 @@
}
*result = false;
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;
@@ -736,6 +777,10 @@
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) {
@@ -788,6 +833,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__)
@@ -795,6 +841,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)
@@ -804,12 +851,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
@@ -866,6 +918,7 @@
IPCThreadState* threadState) const
{
if (auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
// StrictModePolicy.
int32_t strictPolicy = readInt32();
if (threadState == nullptr) {
@@ -891,6 +944,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.
@@ -1401,6 +1459,7 @@
}
}
+#ifdef BINDER_WITH_KERNEL_IPC
flat_binder_object obj;
obj.hdr.type = BINDER_TYPE_FD;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
@@ -1408,6 +1467,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)
@@ -1561,6 +1626,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) {
@@ -1603,6 +1669,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()
@@ -1620,6 +1692,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:
@@ -1672,6 +1745,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
@@ -2164,6 +2241,7 @@
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) {
@@ -2171,6 +2249,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
}
int Parcel::readParcelFileDescriptor() const {
@@ -2326,6 +2408,8 @@
return err;
}
+
+#ifdef BINDER_WITH_KERNEL_IPC
const flat_binder_object* Parcel::readObject(bool nullMetaData) const
{
const auto* kernelFields = maybeKernelFields();
@@ -2391,9 +2475,11 @@
}
return nullptr;
}
+#endif // BINDER_WITH_KERNEL_IPC
void Parcel::closeFileDescriptors() {
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);
@@ -2407,6 +2493,9 @@
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();
}
@@ -2454,6 +2543,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];
@@ -2484,6 +2574,10 @@
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
}
status_t Parcel::rpcSetDataReference(
@@ -2534,6 +2628,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();
@@ -2545,6 +2640,7 @@
<< TypeCode(flat->hdr.type & 0x7f7f7f00) << " = " << flat->binder;
}
}
+#endif // BINDER_WITH_KERNEL_IPC
} else {
to << "NULL";
}
@@ -2559,6 +2655,7 @@
return;
}
+#ifdef BINDER_WITH_KERNEL_IPC
size_t i = kernelFields->mObjectsSize;
if (i == 0) {
return;
@@ -2571,6 +2668,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()
@@ -2580,6 +2678,7 @@
return;
}
+#ifdef BINDER_WITH_KERNEL_IPC
size_t i = kernelFields->mObjectsSize;
if (i == 0) {
return;
@@ -2592,6 +2691,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()
@@ -2813,6 +2913,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++) {
@@ -2841,6 +2942,9 @@
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) {
@@ -2958,6 +3062,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
@@ -2990,6 +3095,7 @@
}
return openAshmemSize;
}
+#endif // BINDER_WITH_KERNEL_IPC
// --- Parcel::Blob ---
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index f83bb5e..096d5cc 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -32,7 +32,9 @@
#include <log/log.h>
#include <utils/Compat.h>
+#include "BuildFlags.h"
#include "FdTrigger.h"
+#include "OS.h"
#include "RpcSocketAddress.h"
#include "RpcState.h"
#include "RpcWireFormat.h"
@@ -131,27 +133,27 @@
}
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");
@@ -159,7 +161,7 @@
}
std::vector<uint8_t> RpcServer::getCertificate(RpcCertificateFormat format) {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
return mCtx->getCertificate(format);
}
@@ -168,15 +170,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;
@@ -204,24 +208,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;
@@ -232,10 +243,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, "
@@ -263,7 +280,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;
@@ -273,7 +290,7 @@
}
size_t RpcServer::numUninitializedSessions() {
- std::lock_guard<std::mutex> _l(mLock);
+ RpcMutexLockGuard _l(mLock);
return mConnectingThreads.size();
}
@@ -354,12 +371,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);
@@ -404,7 +421,9 @@
session->setMaxIncomingThreads(server->mMaxThreads);
if (!session->setProtocolVersion(protocolVersion)) return;
- if (server->mSupportedFileDescriptorTransportModes.test(
+ if (header.fileDescriptorTransportMode <
+ server->mSupportedFileDescriptorTransportModes.size() &&
+ server->mSupportedFileDescriptorTransportModes.test(
header.fileDescriptorTransportMode)) {
session->setFileDescriptorTransportMode(
static_cast<RpcSession::FileDescriptorTransportMode>(
@@ -505,7 +524,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());
@@ -519,17 +538,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 41842a7..80f6a37 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>
@@ -38,6 +37,7 @@
#include <utils/String8.h>
#include "FdTrigger.h"
+#include "OS.h"
#include "RpcSocketAddress.h"
#include "RpcState.h"
#include "RpcWireFormat.h"
@@ -60,7 +60,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 +77,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 +86,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 +100,7 @@
}
size_t RpcSession::getMaxOutgoingThreads() {
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
return mMaxOutgoingThreads;
}
@@ -113,7 +113,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,7 +125,7 @@
}
std::optional<uint32_t> RpcSession::getProtocolVersion() {
- std::lock_guard<std::mutex> _l(mMutex);
+ RpcMutexLockGuard _l(mMutex);
return mProtocolVersion;
}
@@ -209,7 +209,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();
@@ -222,6 +222,7 @@
}
_l.unlock();
+
mRpcBinderState->clear();
return true;
@@ -256,7 +257,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.");
}
@@ -282,7 +283,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))) {
@@ -293,11 +294,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);
}
}
@@ -404,8 +405,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);
@@ -438,7 +439,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());
@@ -500,7 +501,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.",
@@ -655,14 +660,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;
@@ -678,6 +683,7 @@
RpcSession::join(std::move(session), std::move(setupResult));
});
+ rpcJoinIfSingleThreaded(thread);
joinCv.wait(lock, [&] { return ownershipTransferred; });
LOG_ALWAYS_FATAL_IF(!ownershipTransferred);
return OK;
@@ -697,9 +703,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);
}
@@ -736,7 +742,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)",
@@ -754,7 +760,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();
@@ -763,7 +769,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()) {
@@ -781,7 +787,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();
@@ -799,8 +805,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 8f104bc..0ae75cd 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -36,7 +36,6 @@
namespace android {
-using base::ScopeGuard;
using base::StringPrintf;
#if RPC_FLAKE_PRONE
@@ -45,7 +44,7 @@
[[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);
@@ -89,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
@@ -165,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()) {
@@ -200,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);
@@ -228,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(),
@@ -488,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(),
@@ -671,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(),
@@ -733,20 +732,24 @@
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),
- .context = "processing binder RPC command",
+ .context = "processing binder RPC command (where RpcServer::setPerSessionRootObject is "
+ "used to distinguish callers)",
};
const IPCThreadState::SpGuard* origGuard;
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:
@@ -840,7 +843,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);
@@ -981,7 +984,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;
@@ -1089,7 +1092,7 @@
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);
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index b452a99..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>
@@ -268,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/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 0232f50..c91d56c 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -28,9 +28,6 @@
"name": "binderLibTest"
},
{
- "name": "binderRpcTest"
- },
- {
"name": "binderStabilityTest"
},
{
@@ -84,7 +81,21 @@
"name": "rustBinderSerializationTest"
}
],
- "hwasan-presubmit": [
+ "presubmit-large": [
+ {
+ "name": "binderRpcTest"
+ },
+ {
+ "name": "binderRpcTestNoKernel"
+ },
+ {
+ "name": "binderRpcTestSingleThreaded"
+ },
+ {
+ "name": "binderRpcTestSingleThreadedNoKernel"
+ }
+ ],
+ "hwasan-presubmit": [
{
"name": "binderLibTest"
}
diff --git a/libs/binder/Utils.cpp b/libs/binder/Utils.cpp
index b0289a7..0314b0f 100644
--- a/libs/binder/Utils.cpp
+++ b/libs/binder/Utils.cpp
@@ -16,40 +16,12 @@
#include "Utils.h"
-#include <android-base/file.h>
#include <string.h>
-using android::base::ErrnoError;
-using android::base::Result;
-
namespace android {
void zeroMemory(uint8_t* data, size_t size) {
memset(data, 0, size);
}
-Result<void> setNonBlocking(android::base::borrowed_fd fd) {
- int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL));
- if (flags == -1) {
- return ErrnoError() << "Could not get flags for fd";
- }
- if (int ret = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_SETFL, flags | O_NONBLOCK)); ret == -1) {
- return ErrnoError() << "Could not set non-blocking flag for fd";
- }
- return {};
-}
-
-status_t getRandomBytes(uint8_t* data, size_t size) {
- int ret = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
- if (ret == -1) {
- return -errno;
- }
-
- base::unique_fd fd(ret);
- if (!base::ReadFully(fd, data, size)) {
- return -errno;
- }
- return OK;
-}
-
} // namespace android
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index 37c1262..7c6d6f1 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -15,11 +15,10 @@
*/
#include <stddef.h>
+#include <sys/uio.h>
#include <cstdint>
#include <optional>
-#include <android-base/result.h>
-#include <android-base/unique_fd.h>
#include <log/log.h>
#include <utils/Errors.h>
@@ -36,10 +35,6 @@
// avoid optimizations
void zeroMemory(uint8_t* data, size_t size);
-android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);
-
-status_t getRandomBytes(uint8_t* data, size_t size);
-
// View of contiguous sequence. Similar to std::span.
template <typename T>
struct Span {
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index cd6a274..8ce3bc9 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -28,6 +28,10 @@
// ---------------------------------------------------------------------------
namespace android {
+/**
+ * Kernel binder thread state. All operations here refer to kernel binder. This
+ * object is allocated per-thread.
+ */
class IPCThreadState
{
public:
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 32b0ded..91febbd 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -1184,10 +1184,20 @@
c->clear(); // must clear before resizing/reserving otherwise move ctors may be called.
if constexpr (is_pointer_equivalent_array_v<T>) {
// could consider POD without gaps and alignment of 4.
- auto data = reinterpret_cast<const T*>(
- readInplace(static_cast<size_t>(size) * sizeof(T)));
+ size_t dataLen;
+ if (__builtin_mul_overflow(size, sizeof(T), &dataLen)) {
+ return -EOVERFLOW;
+ }
+ auto data = reinterpret_cast<const T*>(readInplace(dataLen));
if (data == nullptr) return BAD_VALUE;
- c->insert(c->begin(), data, data + size); // insert should do a reserve().
+ // std::vector::insert and similar methods will require type-dependent
+ // byte alignment when inserting from a const iterator such as `data`,
+ // e.g. 8 byte alignment for int64_t, and so will not work if `data`
+ // is 4 byte aligned (which is all Parcel guarantees). Copying
+ // the contents into the vector directly, where possible, circumvents
+ // this.
+ c->resize(size);
+ memcpy(c->data(), data, dataLen);
} else if constexpr (std::is_same_v<T, bool>
|| std::is_same_v<T, char16_t>) {
c->reserve(size); // avoids default initialization
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index e17a76c..882dfbf 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -29,6 +29,10 @@
class IPCThreadState;
+/**
+ * Kernel binder process state. All operations here refer to kernel binder. This
+ * object is allocated per process.
+ */
class ProcessState : public virtual RefBase {
public:
static sp<ProcessState> self();
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 7fea76e..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>
@@ -207,16 +208,17 @@
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 b98b0eb..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 {
@@ -218,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;
@@ -244,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
@@ -340,14 +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;
@@ -356,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/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 3824a1b..f3f2886 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -146,8 +146,8 @@
AIBinder_Class_disableInterfaceTokenHeader;
AIBinder_DeathRecipient_setOnUnlinked;
AIBinder_isHandlingTransaction;
- AIBinder_setInheritRt; # llndk
- AIBinder_setMinSchedulerPolicy; # llndk
+ AIBinder_setInheritRt; # apex llndk
+ AIBinder_setMinSchedulerPolicy; # apex llndk
AParcel_marshal;
AParcel_unmarshal;
};
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 2f96d0e..d7c6d49 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -141,6 +141,7 @@
unstable: true,
srcs: [
"BinderRpcTestClientInfo.aidl",
+ "BinderRpcTestServerConfig.aidl",
"BinderRpcTestServerInfo.aidl",
"IBinderRpcCallback.aidl",
"IBinderRpcSession.aidl",
@@ -167,7 +168,6 @@
"libbinder_tls_shared_deps",
],
shared_libs: [
- "libbinder",
"libbase",
"liblog",
],
@@ -185,25 +185,72 @@
],
}
-cc_test {
- name: "binderRpcTest",
+cc_defaults {
+ name: "binderRpcTest_common_defaults",
host_supported: true,
target: {
darwin: {
enabled: false,
},
+ },
+ defaults: [
+ "binder_test_defaults",
+ ],
+
+ static_libs: [
+ "libbinder_tls_static",
+ "libbinder_tls_test_utils",
+ "binderRpcTestIface-cpp",
+ "binderRpcTestIface-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "binderRpcTest_service_defaults",
+ defaults: [
+ "binderRpcTest_common_defaults",
+ ],
+ gtest: false,
+ auto_gen_config: false,
+ srcs: [
+ "binderRpcTestCommon.cpp",
+ "binderRpcTestService.cpp",
+ ],
+}
+
+cc_defaults {
+ name: "binderRpcTest_defaults",
+ target: {
android: {
test_suites: ["vts"],
},
},
defaults: [
- "binder_test_defaults",
- "libbinder_tls_shared_deps",
+ "binderRpcTest_common_defaults",
],
srcs: [
"binderRpcTest.cpp",
+ "binderRpcTestCommon.cpp",
],
+
+ test_suites: ["general-tests"],
+ require_root: true,
+
+ data_bins: [
+ "binder_rpc_test_service",
+ "binder_rpc_test_service_no_kernel",
+ "binder_rpc_test_service_single_threaded",
+ "binder_rpc_test_service_single_threaded_no_kernel",
+ ],
+}
+
+cc_defaults {
+ name: "binderRpcTest_shared_defaults",
+ cflags: [
+ "-DBINDER_WITH_KERNEL_IPC",
+ ],
+
shared_libs: [
"libbinder",
"libbinder_ndk",
@@ -212,14 +259,128 @@
"libcutils",
"liblog",
],
- static_libs: [
- "libbinder_tls_static",
- "libbinder_tls_test_utils",
- "binderRpcTestIface-cpp",
- "binderRpcTestIface-ndk",
+}
+
+cc_defaults {
+ name: "binderRpcTest_static_defaults",
+
+ shared_libs: [
+ "libutils",
+ // libcrypto_static is not visible to this module
+ "libcrypto",
],
- test_suites: ["general-tests"],
- require_root: true,
+ static_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ "libssl",
+ ],
+
+ cflags: [
+ // Disable tests that require shared libraries,
+ // e.g., libbinder.so or libbinder_ndk.so
+ "-DBINDER_TEST_NO_SHARED_LIBS",
+ ],
+}
+
+cc_test {
+ // The module name cannot start with "binderRpcTest" because
+ // then atest tries to execute it as part of binderRpcTest
+ name: "binder_rpc_test_service",
+ defaults: [
+ "binderRpcTest_service_defaults",
+ "binderRpcTest_shared_defaults",
+ "libbinder_tls_shared_deps",
+ ],
+}
+
+cc_test {
+ name: "binder_rpc_test_service_no_kernel",
+ defaults: [
+ "binderRpcTest_service_defaults",
+ "binderRpcTest_static_defaults",
+ ],
+ static_libs: [
+ "libbinder_rpc_no_kernel",
+ ],
+}
+
+cc_test {
+ name: "binder_rpc_test_service_single_threaded",
+ defaults: [
+ "binderRpcTest_service_defaults",
+ "binderRpcTest_static_defaults",
+ ],
+ cflags: [
+ "-DBINDER_RPC_SINGLE_THREADED",
+ "-DBINDER_WITH_KERNEL_IPC",
+ ],
+ static_libs: [
+ "libbinder_rpc_single_threaded",
+ ],
+}
+
+cc_test {
+ name: "binder_rpc_test_service_single_threaded_no_kernel",
+ defaults: [
+ "binderRpcTest_service_defaults",
+ "binderRpcTest_static_defaults",
+ ],
+ cflags: [
+ "-DBINDER_RPC_SINGLE_THREADED",
+ ],
+ static_libs: [
+ "libbinder_rpc_single_threaded_no_kernel",
+ ],
+}
+
+cc_test {
+ name: "binderRpcTest",
+ defaults: [
+ "binderRpcTest_defaults",
+ "binderRpcTest_shared_defaults",
+ "libbinder_tls_shared_deps",
+ ],
+}
+
+cc_test {
+ name: "binderRpcTestNoKernel",
+ defaults: [
+ "binderRpcTest_defaults",
+ "binderRpcTest_static_defaults",
+ ],
+ static_libs: [
+ "libbinder_rpc_no_kernel",
+ ],
+}
+
+cc_test {
+ name: "binderRpcTestSingleThreaded",
+ defaults: [
+ "binderRpcTest_defaults",
+ "binderRpcTest_static_defaults",
+ ],
+ cflags: [
+ "-DBINDER_RPC_SINGLE_THREADED",
+ "-DBINDER_WITH_KERNEL_IPC",
+ ],
+ static_libs: [
+ "libbinder_rpc_single_threaded",
+ ],
+}
+
+cc_test {
+ name: "binderRpcTestSingleThreadedNoKernel",
+ defaults: [
+ "binderRpcTest_defaults",
+ "binderRpcTest_static_defaults",
+ ],
+ cflags: [
+ "-DBINDER_RPC_SINGLE_THREADED",
+ ],
+ static_libs: [
+ "libbinder_rpc_single_threaded_no_kernel",
+ ],
}
cc_test {
diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl
new file mode 100644
index 0000000..34d74be
--- /dev/null
+++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+parcelable BinderRpcTestServerConfig {
+ int numThreads;
+ int[] serverSupportedFileDescriptorTransportModes;
+ int socketType;
+ int rpcSecurity;
+ int serverVersion;
+ int vsockPort;
+ @utf8InCpp String addr;
+}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 3766278..4e41d8e 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -14,30 +14,7 @@
* limitations under the License.
*/
-#include <BinderRpcTestClientInfo.h>
-#include <BinderRpcTestServerInfo.h>
-#include <BnBinderRpcCallback.h>
-#include <BnBinderRpcSession.h>
-#include <BnBinderRpcTest.h>
-#include <aidl/IBinderRpcTest.h>
-#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>
-#include <binder/BpBinder.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <binder/RpcServer.h>
-#include <binder/RpcSession.h>
-#include <binder/RpcTlsTestUtils.h>
-#include <binder/RpcTlsUtils.h>
-#include <binder/RpcTransport.h>
-#include <binder/RpcTransportRaw.h>
-#include <binder/RpcTransportTls.h>
#include <gtest/gtest.h>
#include <chrono>
@@ -46,16 +23,12 @@
#include <thread>
#include <type_traits>
+#include <dlfcn.h>
#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"
+#include "binderRpcTestCommon.h"
using namespace std::chrono_literals;
using namespace std::placeholders;
@@ -65,50 +38,14 @@
namespace android {
+#ifdef BINDER_TEST_NO_SHARED_LIBS
+constexpr bool kEnableSharedLibs = false;
+#else
+constexpr bool kEnableSharedLibs = true;
+#endif
+
static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
-const char* kLocalInetAddress = "127.0.0.1";
-
-enum class RpcSecurity { RAW, TLS };
-
-static inline std::vector<RpcSecurity> RpcSecurityValues() {
- return {RpcSecurity::RAW, RpcSecurity::TLS};
-}
-
-static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
- RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr,
- std::unique_ptr<RpcAuth> auth = nullptr) {
- switch (rpcSecurity) {
- case RpcSecurity::RAW:
- return RpcTransportCtxFactoryRaw::make();
- case RpcSecurity::TLS: {
- if (verifier == nullptr) {
- verifier = std::make_shared<RpcCertificateVerifierSimple>();
- }
- if (auth == nullptr) {
- auth = std::make_unique<RpcAuthSelfSigned>();
- }
- return RpcTransportCtxFactoryTls::make(std::move(verifier), std::move(auth));
- }
- default:
- LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
- }
-}
-
-// 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;
@@ -159,213 +96,6 @@
EXPECT_TRUE(stat.isOk()) << stat; \
} while (false)
-class MyBinderRpcSession : public BnBinderRpcSession {
-public:
- static std::atomic<int32_t> gNum;
-
- MyBinderRpcSession(const std::string& name) : mName(name) { gNum++; }
- Status getName(std::string* name) override {
- *name = mName;
- return Status::ok();
- }
- ~MyBinderRpcSession() { gNum--; }
-
-private:
- std::string mName;
-};
-std::atomic<int32_t> MyBinderRpcSession::gNum;
-
-class MyBinderRpcCallback : public BnBinderRpcCallback {
- Status sendCallback(const std::string& value) {
- std::unique_lock _l(mMutex);
- mValues.push_back(value);
- _l.unlock();
- mCv.notify_one();
- return Status::ok();
- }
- Status sendOnewayCallback(const std::string& value) { return sendCallback(value); }
-
-public:
- std::mutex mMutex;
- std::condition_variable mCv;
- std::vector<std::string> mValues;
-};
-
-class MyBinderRpcTest : public BnBinderRpcTest {
-public:
- wp<RpcServer> server;
- int port = 0;
-
- Status sendString(const std::string& str) override {
- (void)str;
- return Status::ok();
- }
- Status doubleString(const std::string& str, std::string* strstr) override {
- *strstr = str + str;
- return Status::ok();
- }
- Status getClientPort(int* out) override {
- *out = port;
- return Status::ok();
- }
- Status countBinders(std::vector<int32_t>* out) override {
- sp<RpcServer> spServer = server.promote();
- if (spServer == nullptr) {
- return Status::fromExceptionCode(Status::EX_NULL_POINTER);
- }
- out->clear();
- for (auto session : spServer->listSessions()) {
- size_t count = session->state()->countBinders();
- out->push_back(count);
- }
- return Status::ok();
- }
- Status getNullBinder(sp<IBinder>* out) override {
- out->clear();
- return Status::ok();
- }
- Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
- if (binder == nullptr) {
- std::cout << "Received null binder!" << std::endl;
- return Status::fromExceptionCode(Status::EX_NULL_POINTER);
- }
- *out = binder->pingBinder();
- return Status::ok();
- }
- Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
- *out = binder;
- return Status::ok();
- }
- static sp<IBinder> mHeldBinder;
- Status holdBinder(const sp<IBinder>& binder) override {
- mHeldBinder = binder;
- return Status::ok();
- }
- Status getHeldBinder(sp<IBinder>* held) override {
- *held = mHeldBinder;
- return Status::ok();
- }
- Status nestMe(const sp<IBinderRpcTest>& binder, int count) override {
- if (count <= 0) return Status::ok();
- return binder->nestMe(this, count - 1);
- }
- Status alwaysGiveMeTheSameBinder(sp<IBinder>* out) override {
- static sp<IBinder> binder = new BBinder;
- *out = binder;
- return Status::ok();
- }
- Status openSession(const std::string& name, sp<IBinderRpcSession>* out) override {
- *out = new MyBinderRpcSession(name);
- return Status::ok();
- }
- Status getNumOpenSessions(int32_t* out) override {
- *out = MyBinderRpcSession::gNum;
- return Status::ok();
- }
-
- std::mutex blockMutex;
- Status lock() override {
- blockMutex.lock();
- return Status::ok();
- }
- Status unlockInMsAsync(int32_t ms) override {
- usleep(ms * 1000);
- blockMutex.unlock();
- return Status::ok();
- }
- Status lockUnlock() override {
- std::lock_guard<std::mutex> _l(blockMutex);
- return Status::ok();
- }
-
- Status sleepMs(int32_t ms) override {
- usleep(ms * 1000);
- return Status::ok();
- }
-
- Status sleepMsAsync(int32_t ms) override {
- // In-process binder calls are asynchronous, but the call to this method
- // is synchronous wrt its client. This in/out-process threading model
- // diffentiation is a classic binder leaky abstraction (for better or
- // worse) and is preserved here the way binder sockets plugs itself
- // into BpBinder, as nothing is changed at the higher levels
- // (IInterface) which result in this behavior.
- return sleepMs(ms);
- }
-
- Status doCallback(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
- const std::string& value) override {
- if (callback == nullptr) {
- return Status::fromExceptionCode(Status::EX_NULL_POINTER);
- }
-
- if (delayed) {
- std::thread([=]() {
- ALOGE("Executing delayed callback: '%s'", value.c_str());
- Status status = doCallback(callback, oneway, false, value);
- ALOGE("Delayed callback status: '%s'", status.toString8().c_str());
- }).detach();
- return Status::ok();
- }
-
- if (oneway) {
- return callback->sendOnewayCallback(value);
- }
-
- return callback->sendCallback(value);
- }
-
- Status doCallbackAsync(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
- const std::string& value) override {
- return doCallback(callback, oneway, delayed, value);
- }
-
- Status die(bool cleanup) override {
- if (cleanup) {
- exit(1);
- } else {
- _exit(1);
- }
- }
-
- Status scheduleShutdown() override {
- sp<RpcServer> strongServer = server.promote();
- if (strongServer == nullptr) {
- return Status::fromExceptionCode(Status::EX_NULL_POINTER);
- }
- std::thread([=] {
- LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown");
- }).detach();
- return Status::ok();
- }
-
- Status useKernelBinderCallingId() override {
- // this is WRONG! It does not make sense when using RPC binder, and
- // because it is SO wrong, and so much code calls this, it should abort!
-
- (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));
@@ -383,8 +113,8 @@
android::base::borrowed_fd /* readEnd */)>& f) {
android::base::unique_fd childWriteEnd;
android::base::unique_fd childReadEnd;
- CHECK(android::base::Pipe(&mReadEnd, &childWriteEnd)) << strerror(errno);
- CHECK(android::base::Pipe(&childReadEnd, &mWriteEnd)) << strerror(errno);
+ CHECK(android::base::Pipe(&mReadEnd, &childWriteEnd, 0)) << strerror(errno);
+ CHECK(android::base::Pipe(&childReadEnd, &mWriteEnd, 0)) << strerror(errno);
if (0 == (mPid = fork())) {
// racey: assume parent doesn't crash before this is set
prctl(PR_SET_PDEATHSIG, SIGHUP);
@@ -432,7 +162,7 @@
};
static unsigned int allocateVsockPort() {
- static unsigned int vsockPort = 3456;
+ static unsigned int vsockPort = 34567;
return vsockPort++;
}
@@ -509,28 +239,6 @@
}
};
-enum class SocketType {
- PRECONNECTED,
- UNIX,
- VSOCK,
- INET,
-};
-static inline std::string PrintToString(SocketType socketType) {
- switch (socketType) {
- case SocketType::PRECONNECTED:
- return "preconnected_uds";
- case SocketType::UNIX:
- return "unix_domain_socket";
- case SocketType::VSOCK:
- return "vm_socket";
- case SocketType::INET:
- return "inet_socket";
- default:
- LOG_ALWAYS_FATAL("Unknown socket type");
- return "";
- }
-}
-
static base::unique_fd connectTo(const RpcSocketAddress& addr) {
base::unique_fd serverFd(
TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
@@ -546,29 +254,18 @@
return serverFd;
}
-class BinderRpc
- : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t>> {
+using RunServiceFn = void (*)(android::base::borrowed_fd writeEnd,
+ android::base::borrowed_fd readEnd);
+
+class BinderRpc : public ::testing::TestWithParam<
+ std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t, bool, bool>> {
public:
- struct Options {
- size_t numThreads = 1;
- 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()); }
+ bool singleThreaded() const { return std::get<4>(GetParam()); }
+ bool noKernel() const { return std::get<5>(GetParam()); }
// Whether the test params support sending FDs in parcels.
bool supportsFdTransport() const {
@@ -577,111 +274,59 @@
}
static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
- auto [type, security, clientVersion, serverVersion] = info.param;
- return PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
+ auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
+ auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
- }
-
- static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
- uint64_t length = str.length();
- CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
- CHECK(android::base::WriteFully(fd, str.data(), str.length()));
- }
-
- static inline std::string readString(android::base::borrowed_fd fd) {
- uint64_t length;
- CHECK(android::base::ReadFully(fd, &length, sizeof(length)));
- std::string ret(length, '\0');
- CHECK(android::base::ReadFully(fd, ret.data(), length));
+ if (singleThreaded) {
+ ret += "_single_threaded";
+ }
+ if (noKernel) {
+ ret += "_no_kernel";
+ }
return ret;
}
- static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) {
- Parcel parcel;
- CHECK_EQ(OK, parcelable.writeToParcel(&parcel));
- writeString(fd,
- std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize()));
- }
-
- template <typename T>
- static inline T readFromFd(android::base::borrowed_fd fd) {
- std::string data = readString(fd);
- Parcel parcel;
- CHECK_EQ(OK, parcel.setData(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
- T object;
- CHECK_EQ(OK, object.readFromParcel(&parcel));
- return object;
- }
-
// This creates a new process serving an interface on a certain number of
// threads.
- ProcessSession createRpcTestSocketServerProcess(
- const Options& options, const std::function<void(const sp<RpcServer>&)>& configure) {
+ ProcessSession createRpcTestSocketServerProcessEtc(const BinderRpcOptions& options) {
CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
SocketType socketType = std::get<0>(GetParam());
RpcSecurity rpcSecurity = std::get<1>(GetParam());
uint32_t clientVersion = std::get<2>(GetParam());
uint32_t serverVersion = std::get<3>(GetParam());
+ bool singleThreaded = std::get<4>(GetParam());
+ bool noKernel = std::get<5>(GetParam());
- unsigned int vsockPort = allocateVsockPort();
- std::string addr = allocateSocketAddress();
+ std::string path = android::base::GetExecutableDirectory();
+ auto servicePath =
+ android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(),
+ singleThreaded ? "_single_threaded" : "",
+ noKernel ? "_no_kernel" : "");
auto ret = ProcessSession{
.host = Process([=](android::base::borrowed_fd writeEnd,
android::base::borrowed_fd readEnd) {
- auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
- sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
-
- server->setProtocolVersion(serverVersion);
- server->setMaxThreads(options.numThreads);
- server->setSupportedFileDescriptorTransportModes(
- options.serverSupportedFileDescriptorTransportModes);
-
- unsigned int outPort = 0;
-
- switch (socketType) {
- case SocketType::PRECONNECTED:
- [[fallthrough]];
- case SocketType::UNIX:
- CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str())) << addr;
- break;
- case SocketType::VSOCK:
- CHECK_EQ(OK, server->setupVsockServer(vsockPort));
- break;
- case SocketType::INET: {
- CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
- CHECK_NE(0, outPort);
- break;
- }
- default:
- LOG_ALWAYS_FATAL("Unknown socket type");
- }
-
- BinderRpcTestServerInfo serverInfo;
- serverInfo.port = static_cast<int64_t>(outPort);
- serverInfo.cert.data = server->getCertificate(RpcCertificateFormat::PEM);
- writeToFd(writeEnd, serverInfo);
- auto clientInfo = readFromFd<BinderRpcTestClientInfo>(readEnd);
-
- if (rpcSecurity == RpcSecurity::TLS) {
- for (const auto& clientCert : clientInfo.certs) {
- CHECK_EQ(OK,
- certVerifier
- ->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
- clientCert.data));
- }
- }
-
- configure(server);
-
- server->join();
-
- // Another thread calls shutdown. Wait for it to complete.
- (void)server->shutdown();
+ auto writeFd = std::to_string(writeEnd.get());
+ auto readFd = std::to_string(readEnd.get());
+ execl(servicePath.c_str(), servicePath.c_str(), writeFd.c_str(), readFd.c_str(),
+ NULL);
}),
};
+ BinderRpcTestServerConfig serverConfig;
+ serverConfig.numThreads = options.numThreads;
+ serverConfig.socketType = static_cast<int32_t>(socketType);
+ serverConfig.rpcSecurity = static_cast<int32_t>(rpcSecurity);
+ serverConfig.serverVersion = serverVersion;
+ serverConfig.vsockPort = allocateVsockPort();
+ serverConfig.addr = allocateSocketAddress();
+ for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
+ serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
+ static_cast<int32_t>(mode));
+ }
+ writeToFd(ret.host.writeEnd(), serverConfig);
+
std::vector<sp<RpcSession>> sessions;
auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
for (size_t i = 0; i < options.numSessions; i++) {
@@ -719,14 +364,14 @@
switch (socketType) {
case SocketType::PRECONNECTED:
status = session->setupPreconnectedClient({}, [=]() {
- return connectTo(UnixSocketAddress(addr.c_str()));
+ return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
});
break;
case SocketType::UNIX:
- status = session->setupUnixDomainClient(addr.c_str());
+ status = session->setupUnixDomainClient(serverConfig.addr.c_str());
break;
case SocketType::VSOCK:
- status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
+ status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort);
break;
case SocketType::INET:
status = session->setupInetClient("127.0.0.1", serverInfo.port);
@@ -744,46 +389,9 @@
return ret;
}
- BinderRpcTestProcessSession createRpcTestSocketServerProcess(const Options& options) {
+ BinderRpcTestProcessSession createRpcTestSocketServerProcess(const BinderRpcOptions& options) {
BinderRpcTestProcessSession ret{
- .proc = createRpcTestSocketServerProcess(
- options,
- [&](const sp<RpcServer>& server) {
- server->setPerSessionRootObject([&](const void* addrPtr, size_t len) {
- // UNIX sockets with abstract addresses return
- // sizeof(sa_family_t)==2 in addrlen
- CHECK_GE(len, sizeof(sa_family_t));
- const sockaddr* addr = reinterpret_cast<const sockaddr*>(addrPtr);
- sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make();
- switch (addr->sa_family) {
- case AF_UNIX:
- // nothing to save
- break;
- case AF_VSOCK:
- CHECK_EQ(len, sizeof(sockaddr_vm));
- service->port = reinterpret_cast<const sockaddr_vm*>(addr)
- ->svm_port;
- break;
- case AF_INET:
- CHECK_EQ(len, sizeof(sockaddr_in));
- service->port =
- ntohs(reinterpret_cast<const sockaddr_in*>(addr)
- ->sin_port);
- break;
- case AF_INET6:
- CHECK_EQ(len, sizeof(sockaddr_in));
- service->port =
- ntohs(reinterpret_cast<const sockaddr_in6*>(addr)
- ->sin6_port);
- break;
- default:
- LOG_ALWAYS_FATAL("Unrecognized address family %d",
- addr->sa_family);
- }
- service->server = server;
- return service;
- });
- }),
+ .proc = createRpcTestSocketServerProcessEtc(options),
};
ret.rootBinder = ret.proc.sessions.empty() ? nullptr : ret.proc.sessions.at(0).root;
@@ -796,6 +404,18 @@
size_t sleepMs = 500);
};
+// Test fixture for tests that start multiple threads.
+// This includes tests with one thread but multiple sessions,
+// since a server uses one thread per session.
+class BinderRpcThreads : public BinderRpc {
+public:
+ void SetUp() override {
+ if constexpr (!kEnableRpcThreads) {
+ GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+ }
+ }
+};
+
TEST_P(BinderRpc, Ping) {
auto proc = createRpcTestSocketServerProcess({});
ASSERT_NE(proc.rootBinder, nullptr);
@@ -808,7 +428,7 @@
EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
}
-TEST_P(BinderRpc, MultipleSessions) {
+TEST_P(BinderRpcThreads, MultipleSessions) {
auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
for (auto session : proc.proc.sessions) {
ASSERT_NE(nullptr, session.root);
@@ -816,7 +436,7 @@
}
}
-TEST_P(BinderRpc, SeparateRootObject) {
+TEST_P(BinderRpcThreads, SeparateRootObject) {
SocketType type = std::get<0>(GetParam());
if (type == SocketType::PRECONNECTED || type == SocketType::UNIX) {
// we can't get port numbers for unix sockets
@@ -999,7 +619,7 @@
proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
}
-TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
+TEST_P(BinderRpcThreads, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
sp<IBinder> outBinder;
@@ -1009,6 +629,11 @@
}
TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
+ if (!kEnableKernelIpc || noKernel()) {
+ GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+ "at build time.";
+ }
+
auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
@@ -1018,6 +643,11 @@
}
TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
+ if (!kEnableKernelIpc || noKernel()) {
+ GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+ "at build time.";
+ }
+
auto proc = createRpcTestSocketServerProcess({});
// for historical reasons, IServiceManager interface only returns the
@@ -1145,7 +775,7 @@
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
}
-TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
+TEST_P(BinderRpcThreads, ThreadPoolGreaterThanEqualRequested) {
constexpr size_t kNumThreads = 10;
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
@@ -1196,14 +826,14 @@
EXPECT_LE(epochMsAfter, epochMsBefore + 3 * sleepMs);
}
-TEST_P(BinderRpc, ThreadPoolOverSaturated) {
+TEST_P(BinderRpcThreads, ThreadPoolOverSaturated) {
constexpr size_t kNumThreads = 10;
constexpr size_t kNumCalls = kNumThreads + 3;
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
}
-TEST_P(BinderRpc, ThreadPoolLimitOutgoing) {
+TEST_P(BinderRpcThreads, ThreadPoolLimitOutgoing) {
constexpr size_t kNumThreads = 20;
constexpr size_t kNumOutgoingConnections = 10;
constexpr size_t kNumCalls = kNumOutgoingConnections + 3;
@@ -1212,7 +842,7 @@
testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
}
-TEST_P(BinderRpc, ThreadingStressTest) {
+TEST_P(BinderRpcThreads, ThreadingStressTest) {
constexpr size_t kNumClientThreads = 10;
constexpr size_t kNumServerThreads = 10;
constexpr size_t kNumCalls = 100;
@@ -1241,7 +871,7 @@
for (auto& t : threads) t.join();
}
-TEST_P(BinderRpc, OnewayStressTest) {
+TEST_P(BinderRpcThreads, OnewayStressTest) {
constexpr size_t kNumClientThreads = 10;
constexpr size_t kNumServerThreads = 10;
constexpr size_t kNumCalls = 1000;
@@ -1276,7 +906,7 @@
EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
}
-TEST_P(BinderRpc, OnewayCallQueueing) {
+TEST_P(BinderRpcThreads, OnewayCallQueueing) {
constexpr size_t kNumSleeps = 10;
constexpr size_t kNumExtraServerThreads = 4;
constexpr size_t kSleepMs = 50;
@@ -1305,7 +935,7 @@
saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface);
}
-TEST_P(BinderRpc, OnewayCallExhaustion) {
+TEST_P(BinderRpcThreads, OnewayCallExhaustion) {
constexpr size_t kNumClients = 2;
constexpr size_t kTooLongMs = 1000;
@@ -1348,11 +978,21 @@
TEST_P(BinderRpc, Callbacks) {
const static std::string kTestString = "good afternoon!";
+ bool bothSingleThreaded = !kEnableRpcThreads || singleThreaded();
+
for (bool callIsOneway : {true, false}) {
for (bool callbackIsOneway : {true, false}) {
for (bool delayed : {true, false}) {
+ if (bothSingleThreaded && (callIsOneway || callbackIsOneway || delayed)) {
+ // we have no incoming connections to receive the callback
+ continue;
+ }
+
+ size_t numIncomingConnections = bothSingleThreaded ? 0 : 1;
auto proc = createRpcTestSocketServerProcess(
- {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+ {.numThreads = 1,
+ .numSessions = 1,
+ .numIncomingConnections = numIncomingConnections});
auto cb = sp<MyBinderRpcCallback>::make();
if (callIsOneway) {
@@ -1368,7 +1008,7 @@
// the callback will be processed on another thread.
if (callIsOneway || callbackIsOneway || delayed) {
using std::literals::chrono_literals::operator""s;
- std::unique_lock<std::mutex> _l(cb->mMutex);
+ RpcMutexUniqueLock _l(cb->mMutex);
cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
}
@@ -1434,20 +1074,23 @@
}
TEST_P(BinderRpc, UseKernelBinderCallingId) {
- bool okToFork = ProcessState::selfOrNull() == nullptr;
+ // This test only works if the current process shared the internal state of
+ // ProcessState with the service across the call to fork(). Both the static
+ // libraries and libbinder.so have their own separate copies of all the
+ // globals, so the test only works when the test client and service both use
+ // libbinder.so (when using static libraries, even a client and service
+ // using the same kind of static library should have separate copies of the
+ // variables).
+ if (!kEnableSharedLibs || singleThreaded() || noKernel()) {
+ GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+ "at build time.";
+ }
auto proc = createRpcTestSocketServerProcess({});
- // If this process has used ProcessState already, then the forked process
- // cannot use it at all. If this process hasn't used it (depending on the
- // order tests are run), then the forked process can use it, and we'll only
- // catch the invalid usage the second time. Such is the burden of global
- // state!
- if (okToFork) {
- // we can't allocate IPCThreadState so actually the first time should
- // succeed :(
- EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
- }
+ // we can't allocate IPCThreadState so actually the first time should
+ // succeed :(
+ EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
// second time! we catch the error :)
EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
@@ -1597,6 +1240,10 @@
}
TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
+ if constexpr (!kEnableSharedLibs) {
+ GTEST_SKIP() << "Test disabled because Binder was built as a static library";
+ }
+
auto proc = createRpcTestSocketServerProcess({});
ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
@@ -1606,6 +1253,10 @@
}
TEST_P(BinderRpc, WorksWithLibbinderNdkUserTransaction) {
+ if constexpr (!kEnableSharedLibs) {
+ GTEST_SKIP() << "Test disabled because Binder was built as a static library";
+ }
+
auto proc = createRpcTestSocketServerProcess({});
ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
@@ -1630,7 +1281,7 @@
return ret;
}
-TEST_P(BinderRpc, Fds) {
+TEST_P(BinderRpcThreads, Fds) {
ssize_t beforeFds = countFds();
ASSERT_GE(beforeFds, 0);
{
@@ -1766,7 +1417,18 @@
::testing::Combine(::testing::ValuesIn(testSocketTypes()),
::testing::ValuesIn(RpcSecurityValues()),
::testing::ValuesIn(testVersions()),
- ::testing::ValuesIn(testVersions())),
+ ::testing::ValuesIn(testVersions()),
+ ::testing::Values(false, true),
+ ::testing::Values(false, true)),
+ BinderRpc::PrintParamInfo);
+
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpcThreads,
+ ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
+ ::testing::ValuesIn(RpcSecurityValues()),
+ ::testing::ValuesIn(testVersions()),
+ ::testing::ValuesIn(testVersions()),
+ ::testing::Values(false),
+ ::testing::Values(false, true)),
BinderRpc::PrintParamInfo);
class BinderRpcServerRootObject
@@ -1821,6 +1483,10 @@
};
TEST_P(BinderRpcServerOnly, Shutdown) {
+ if constexpr (!kEnableRpcThreads) {
+ GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+ }
+
auto addr = allocateSocketAddress();
auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
server->setProtocolVersion(std::get<1>(GetParam()));
@@ -1852,6 +1518,11 @@
"createRpcDelegateServiceManager() with a device attached, such test belongs "
"to binderHostDeviceTest. Hence, just disable this test on host.";
#endif // !__ANDROID__
+ if constexpr (!kEnableKernelIpc) {
+ GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+ "at build time.";
+ }
+
sp<IServiceManager> sm = defaultServiceManager();
ASSERT_NE(nullptr, sm);
// Any Java service with non-empty getInterfaceDescriptor() would do.
@@ -2152,6 +1823,11 @@
(void)serverVersion;
return RpcTransportTestUtils::trust(rpcSecurity, certificateFormat, a, b);
}
+ void SetUp() override {
+ if constexpr (!kEnableRpcThreads) {
+ GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+ }
+ }
};
TEST_P(RpcTransportTest, GoodCertificate) {
@@ -2356,6 +2032,10 @@
};
TEST_P(RpcTransportTlsKeyTest, PreSignedCertificate) {
+ if constexpr (!kEnableRpcThreads) {
+ GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+ }
+
auto [socketType, certificateFormat, keyFormat, serverVersion] = GetParam();
std::vector<uint8_t> pkeyData, certData;
diff --git a/libs/binder/tests/binderRpcTestCommon.cpp b/libs/binder/tests/binderRpcTestCommon.cpp
new file mode 100644
index 0000000..0d9aa95
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestCommon.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#include "binderRpcTestCommon.h"
+
+namespace android {
+
+std::atomic<int32_t> MyBinderRpcSession::gNum;
+sp<IBinder> MyBinderRpcTest::mHeldBinder;
+
+} // namespace android
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
new file mode 100644
index 0000000..4513d36
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -0,0 +1,379 @@
+/*
+ * 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 <BinderRpcTestClientInfo.h>
+#include <BinderRpcTestServerConfig.h>
+#include <BinderRpcTestServerInfo.h>
+#include <BnBinderRpcCallback.h>
+#include <BnBinderRpcSession.h>
+#include <BnBinderRpcTest.h>
+#include <aidl/IBinderRpcTest.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_libbinder.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcThreads.h>
+#include <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTlsUtils.h>
+#include <binder/RpcTransport.h>
+#include <binder/RpcTransportRaw.h>
+#include <binder/RpcTransportTls.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+
+#include <signal.h>
+
+#include "../BuildFlags.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"
+
+namespace android {
+
+constexpr char kLocalInetAddress[] = "127.0.0.1";
+
+enum class RpcSecurity { RAW, TLS };
+
+static inline std::vector<RpcSecurity> RpcSecurityValues() {
+ return {RpcSecurity::RAW, RpcSecurity::TLS};
+}
+
+enum class SocketType {
+ PRECONNECTED,
+ UNIX,
+ VSOCK,
+ INET,
+};
+static inline std::string PrintToString(SocketType socketType) {
+ switch (socketType) {
+ case SocketType::PRECONNECTED:
+ return "preconnected_uds";
+ case SocketType::UNIX:
+ return "unix_domain_socket";
+ case SocketType::VSOCK:
+ return "vm_socket";
+ case SocketType::INET:
+ return "inet_socket";
+ default:
+ LOG_ALWAYS_FATAL("Unknown socket type");
+ return "";
+ }
+}
+
+struct BinderRpcOptions {
+ size_t numThreads = 1;
+ 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;
+};
+
+static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
+ uint64_t length = str.length();
+ CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
+ CHECK(android::base::WriteFully(fd, str.data(), str.length()));
+}
+
+static inline std::string readString(android::base::borrowed_fd fd) {
+ uint64_t length;
+ CHECK(android::base::ReadFully(fd, &length, sizeof(length)));
+ std::string ret(length, '\0');
+ CHECK(android::base::ReadFully(fd, ret.data(), length));
+ return ret;
+}
+
+static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) {
+ Parcel parcel;
+ CHECK_EQ(OK, parcelable.writeToParcel(&parcel));
+ writeString(fd, std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize()));
+}
+
+template <typename T>
+static inline T readFromFd(android::base::borrowed_fd fd) {
+ std::string data = readString(fd);
+ Parcel parcel;
+ CHECK_EQ(OK, parcel.setData(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
+ T object;
+ CHECK_EQ(OK, object.readFromParcel(&parcel));
+ return object;
+}
+
+static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
+ RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr,
+ std::unique_ptr<RpcAuth> auth = nullptr) {
+ switch (rpcSecurity) {
+ case RpcSecurity::RAW:
+ return RpcTransportCtxFactoryRaw::make();
+ case RpcSecurity::TLS: {
+ if (verifier == nullptr) {
+ verifier = std::make_shared<RpcCertificateVerifierSimple>();
+ }
+ if (auth == nullptr) {
+ auth = std::make_unique<RpcAuthSelfSigned>();
+ }
+ return RpcTransportCtxFactoryTls::make(std::move(verifier), std::move(auth));
+ }
+ default:
+ LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
+ }
+}
+
+// Create an FD that returns `contents` when read.
+static inline base::unique_fd mockFileDescriptor(std::string contents) {
+ android::base::unique_fd readFd, writeFd;
+ CHECK(android::base::Pipe(&readFd, &writeFd)) << strerror(errno);
+ RpcMaybeThread([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;
+ LOG_ALWAYS_FATAL_IF(EPIPE != savedErrno, "mockFileDescriptor write failed: %s",
+ strerror(savedErrno));
+ }
+ }).detach();
+ return readFd;
+}
+
+using android::binder::Status;
+
+class MyBinderRpcSession : public BnBinderRpcSession {
+public:
+ static std::atomic<int32_t> gNum;
+
+ MyBinderRpcSession(const std::string& name) : mName(name) { gNum++; }
+ Status getName(std::string* name) override {
+ *name = mName;
+ return Status::ok();
+ }
+ ~MyBinderRpcSession() { gNum--; }
+
+private:
+ std::string mName;
+};
+
+class MyBinderRpcCallback : public BnBinderRpcCallback {
+ Status sendCallback(const std::string& value) {
+ RpcMutexUniqueLock _l(mMutex);
+ mValues.push_back(value);
+ _l.unlock();
+ mCv.notify_one();
+ return Status::ok();
+ }
+ Status sendOnewayCallback(const std::string& value) { return sendCallback(value); }
+
+public:
+ RpcMutex mMutex;
+ RpcConditionVariable mCv;
+ std::vector<std::string> mValues;
+};
+
+class MyBinderRpcTest : public BnBinderRpcTest {
+public:
+ wp<RpcServer> server;
+ int port = 0;
+
+ Status sendString(const std::string& str) override {
+ (void)str;
+ return Status::ok();
+ }
+ Status doubleString(const std::string& str, std::string* strstr) override {
+ *strstr = str + str;
+ return Status::ok();
+ }
+ Status getClientPort(int* out) override {
+ *out = port;
+ return Status::ok();
+ }
+ Status countBinders(std::vector<int32_t>* out) override {
+ sp<RpcServer> spServer = server.promote();
+ if (spServer == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+ out->clear();
+ for (auto session : spServer->listSessions()) {
+ size_t count = session->state()->countBinders();
+ out->push_back(count);
+ }
+ return Status::ok();
+ }
+ Status getNullBinder(sp<IBinder>* out) override {
+ out->clear();
+ return Status::ok();
+ }
+ Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
+ if (binder == nullptr) {
+ std::cout << "Received null binder!" << std::endl;
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+ *out = binder->pingBinder();
+ return Status::ok();
+ }
+ Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
+ *out = binder;
+ return Status::ok();
+ }
+ static sp<IBinder> mHeldBinder;
+ Status holdBinder(const sp<IBinder>& binder) override {
+ mHeldBinder = binder;
+ return Status::ok();
+ }
+ Status getHeldBinder(sp<IBinder>* held) override {
+ *held = mHeldBinder;
+ return Status::ok();
+ }
+ Status nestMe(const sp<IBinderRpcTest>& binder, int count) override {
+ if (count <= 0) return Status::ok();
+ return binder->nestMe(this, count - 1);
+ }
+ Status alwaysGiveMeTheSameBinder(sp<IBinder>* out) override {
+ static sp<IBinder> binder = new BBinder;
+ *out = binder;
+ return Status::ok();
+ }
+ Status openSession(const std::string& name, sp<IBinderRpcSession>* out) override {
+ *out = new MyBinderRpcSession(name);
+ return Status::ok();
+ }
+ Status getNumOpenSessions(int32_t* out) override {
+ *out = MyBinderRpcSession::gNum;
+ return Status::ok();
+ }
+
+ RpcMutex blockMutex;
+ Status lock() override {
+ blockMutex.lock();
+ return Status::ok();
+ }
+ Status unlockInMsAsync(int32_t ms) override {
+ usleep(ms * 1000);
+ blockMutex.unlock();
+ return Status::ok();
+ }
+ Status lockUnlock() override {
+ RpcMutexLockGuard _l(blockMutex);
+ return Status::ok();
+ }
+
+ Status sleepMs(int32_t ms) override {
+ usleep(ms * 1000);
+ return Status::ok();
+ }
+
+ Status sleepMsAsync(int32_t ms) override {
+ // In-process binder calls are asynchronous, but the call to this method
+ // is synchronous wrt its client. This in/out-process threading model
+ // diffentiation is a classic binder leaky abstraction (for better or
+ // worse) and is preserved here the way binder sockets plugs itself
+ // into BpBinder, as nothing is changed at the higher levels
+ // (IInterface) which result in this behavior.
+ return sleepMs(ms);
+ }
+
+ Status doCallback(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
+ const std::string& value) override {
+ if (callback == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+
+ if (delayed) {
+ RpcMaybeThread([=]() {
+ ALOGE("Executing delayed callback: '%s'", value.c_str());
+ Status status = doCallback(callback, oneway, false, value);
+ ALOGE("Delayed callback status: '%s'", status.toString8().c_str());
+ }).detach();
+ return Status::ok();
+ }
+
+ if (oneway) {
+ return callback->sendOnewayCallback(value);
+ }
+
+ return callback->sendCallback(value);
+ }
+
+ Status doCallbackAsync(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
+ const std::string& value) override {
+ return doCallback(callback, oneway, delayed, value);
+ }
+
+ Status die(bool cleanup) override {
+ if (cleanup) {
+ exit(1);
+ } else {
+ _exit(1);
+ }
+ }
+
+ Status scheduleShutdown() override {
+ sp<RpcServer> strongServer = server.promote();
+ if (strongServer == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+ RpcMaybeThread([=] {
+ LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown");
+ }).detach();
+ return Status::ok();
+ }
+
+ Status useKernelBinderCallingId() override {
+ // this is WRONG! It does not make sense when using RPC binder, and
+ // because it is SO wrong, and so much code calls this, it should abort!
+
+ if constexpr (kEnableKernelIpc) {
+ (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();
+ }
+};
+
+} // namespace android
diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp
new file mode 100644
index 0000000..31eb5da
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#include "binderRpcTestCommon.h"
+
+using namespace android;
+
+int main(int argc, const char* argv[]) {
+ LOG_ALWAYS_FATAL_IF(argc != 3, "Invalid number of arguments: %d", argc);
+ base::unique_fd writeEnd(atoi(argv[1]));
+ base::unique_fd readEnd(atoi(argv[2]));
+
+ auto serverConfig = readFromFd<BinderRpcTestServerConfig>(readEnd);
+ auto socketType = static_cast<SocketType>(serverConfig.socketType);
+ auto rpcSecurity = static_cast<RpcSecurity>(serverConfig.rpcSecurity);
+
+ std::vector<RpcSession::FileDescriptorTransportMode>
+ serverSupportedFileDescriptorTransportModes;
+ for (auto mode : serverConfig.serverSupportedFileDescriptorTransportModes) {
+ serverSupportedFileDescriptorTransportModes.push_back(
+ static_cast<RpcSession::FileDescriptorTransportMode>(mode));
+ }
+
+ auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+ sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
+
+ server->setProtocolVersion(serverConfig.serverVersion);
+ server->setMaxThreads(serverConfig.numThreads);
+ server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes);
+
+ unsigned int outPort = 0;
+
+ switch (socketType) {
+ case SocketType::PRECONNECTED:
+ [[fallthrough]];
+ case SocketType::UNIX:
+ CHECK_EQ(OK, server->setupUnixDomainServer(serverConfig.addr.c_str()))
+ << serverConfig.addr;
+ break;
+ case SocketType::VSOCK:
+ CHECK_EQ(OK, server->setupVsockServer(serverConfig.vsockPort));
+ break;
+ case SocketType::INET: {
+ CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
+ CHECK_NE(0, outPort);
+ break;
+ }
+ default:
+ LOG_ALWAYS_FATAL("Unknown socket type");
+ }
+
+ BinderRpcTestServerInfo serverInfo;
+ serverInfo.port = static_cast<int64_t>(outPort);
+ serverInfo.cert.data = server->getCertificate(RpcCertificateFormat::PEM);
+ writeToFd(writeEnd, serverInfo);
+ auto clientInfo = readFromFd<BinderRpcTestClientInfo>(readEnd);
+
+ if (rpcSecurity == RpcSecurity::TLS) {
+ for (const auto& clientCert : clientInfo.certs) {
+ CHECK_EQ(OK,
+ certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+ clientCert.data));
+ }
+ }
+
+ server->setPerSessionRootObject([&](const void* addrPtr, size_t len) {
+ // UNIX sockets with abstract addresses return
+ // sizeof(sa_family_t)==2 in addrlen
+ CHECK_GE(len, sizeof(sa_family_t));
+ const sockaddr* addr = reinterpret_cast<const sockaddr*>(addrPtr);
+ sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make();
+ switch (addr->sa_family) {
+ case AF_UNIX:
+ // nothing to save
+ break;
+ case AF_VSOCK:
+ CHECK_EQ(len, sizeof(sockaddr_vm));
+ service->port = reinterpret_cast<const sockaddr_vm*>(addr)->svm_port;
+ break;
+ case AF_INET:
+ CHECK_EQ(len, sizeof(sockaddr_in));
+ service->port = ntohs(reinterpret_cast<const sockaddr_in*>(addr)->sin_port);
+ break;
+ case AF_INET6:
+ CHECK_EQ(len, sizeof(sockaddr_in));
+ service->port = ntohs(reinterpret_cast<const sockaddr_in6*>(addr)->sin6_port);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unrecognized address family %d", addr->sa_family);
+ }
+ service->server = server;
+ return service;
+ });
+
+ server->join();
+
+ // Another thread calls shutdown. Wait for it to complete.
+ (void)server->shutdown();
+
+ return 0;
+}
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index e543917..a6585c5 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -94,6 +94,7 @@
"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",
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);