diff options
-rw-r--r-- | libs/binder/Android.bp | 4 | ||||
-rw-r--r-- | libs/binder/Binder.cpp | 117 | ||||
-rw-r--r-- | libs/binder/ProcessState.cpp | 8 | ||||
-rw-r--r-- | libs/binder/include/binder/Binder.h | 5 | ||||
-rw-r--r-- | libs/binder/include/binder/IBinder.h | 22 | ||||
-rw-r--r-- | libs/binder/include/binder/ProcessState.h | 7 | ||||
-rw-r--r-- | libs/binder/tests/Android.bp | 2 | ||||
-rw-r--r-- | libs/binder/tests/binderLibTest.cpp | 223 | ||||
-rw-r--r-- | libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h | 5 |
9 files changed, 382 insertions, 11 deletions
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index f157aa27b2..6e7f74feb6 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -167,6 +167,10 @@ cc_library { binder32bit: { cflags: ["-DBINDER_IPC_32BIT=1"], }, + + debuggable: { + cflags: ["-DBINDER_RPC_DEV_SERVERS"], + }, }, shared_libs: [ diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index d5bdd1c803..c83c383513 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -17,16 +17,24 @@ #include <binder/Binder.h> #include <atomic> -#include <utils/misc.h> + +#include <android-base/unique_fd.h> #include <binder/BpBinder.h> #include <binder/IInterface.h> +#include <binder/IPCThreadState.h> #include <binder/IResultReceiver.h> #include <binder/IShellCallback.h> #include <binder/Parcel.h> +#include <binder/RpcServer.h> +#include <private/android_filesystem_config.h> +#include <utils/misc.h> +#include <inttypes.h> #include <linux/sched.h> #include <stdio.h> +#include "RpcState.h" + namespace android { // Service implementations inherit from BBinder and IBinder, and this is frozen @@ -39,6 +47,12 @@ static_assert(sizeof(IBinder) == 12); static_assert(sizeof(BBinder) == 20); #endif +#ifdef BINDER_RPC_DEV_SERVERS +constexpr const bool kEnableRpcDevServers = true; +#else +constexpr const bool kEnableRpcDevServers = false; +#endif + // --------------------------------------------------------------------------- IBinder::IBinder() @@ -136,6 +150,33 @@ status_t IBinder::getDebugPid(pid_t* out) { return OK; } +status_t IBinder::setRpcClientDebug(android::base::unique_fd socketFd, uint32_t maxRpcThreads) { + if constexpr (!kEnableRpcDevServers) { + ALOGW("setRpcClientDebug disallowed because RPC is not enabled"); + return INVALID_OPERATION; + } + + BBinder* local = this->localBinder(); + if (local != nullptr) { + return local->BBinder::setRpcClientDebug(std::move(socketFd), maxRpcThreads); + } + + BpBinder* proxy = this->remoteBinder(); + LOG_ALWAYS_FATAL_IF(proxy == nullptr, "binder object must be either local or remote"); + + Parcel data; + Parcel reply; + status_t status; + if (status = data.writeBool(socketFd.ok()); status != OK) return status; + if (socketFd.ok()) { + // writeUniqueFileDescriptor currently makes an unnecessary dup(). + status = data.writeFileDescriptor(socketFd.release(), true /* own */); + if (status != OK) return status; + } + if (status = data.writeUint32(maxRpcThreads); status != OK) return status; + return transact(SET_RPC_CLIENT_TRANSACTION, data, &reply); +} + // --------------------------------------------------------------------------- class BBinder::Extras @@ -150,6 +191,7 @@ public: // for below objects Mutex mLock; + sp<RpcServer> mRpcServer; BpBinder::ObjectManager mObjects; }; @@ -199,6 +241,10 @@ status_t BBinder::transact( case DEBUG_PID_TRANSACTION: err = reply->writeInt32(getDebugPid()); break; + case SET_RPC_CLIENT_TRANSACTION: { + err = setRpcClientDebug(data); + break; + } default: err = onTransact(code, data, reply, flags); break; @@ -368,6 +414,75 @@ void BBinder::setExtension(const sp<IBinder>& extension) { e->mExtension = extension; } +status_t BBinder::setRpcClientDebug(const Parcel& data) { + if constexpr (!kEnableRpcDevServers) { + ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__); + 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); + return PERMISSION_DENIED; + } + status_t status; + bool hasSocketFd; + android::base::unique_fd clientFd; + uint32_t maxRpcThreads; + + if (status = data.readBool(&hasSocketFd); status != OK) return status; + if (hasSocketFd) { + if (status = data.readUniqueFileDescriptor(&clientFd); status != OK) return status; + } + if (status = data.readUint32(&maxRpcThreads); status != OK) return status; + + return setRpcClientDebug(std::move(clientFd), maxRpcThreads); +} + +status_t BBinder::setRpcClientDebug(android::base::unique_fd socketFd, uint32_t maxRpcThreads) { + if constexpr (!kEnableRpcDevServers) { + ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__); + return INVALID_OPERATION; + } + + const int socketFdForPrint = socketFd.get(); + LOG_RPC_DETAIL("%s(%d, %" PRIu32 ")", __PRETTY_FUNCTION__, socketFdForPrint, maxRpcThreads); + + if (!socketFd.ok()) { + ALOGE("%s: No socket FD provided.", __PRETTY_FUNCTION__); + return BAD_VALUE; + } + if (maxRpcThreads <= 0) { + ALOGE("%s: RPC is useless with %" PRIu32 " threads.", __PRETTY_FUNCTION__, maxRpcThreads); + return BAD_VALUE; + } + + // TODO(b/182914638): RPC and binder should share the same thread pool count. + size_t binderThreadPoolMaxCount = ProcessState::self()->getThreadPoolMaxThreadCount(); + if (binderThreadPoolMaxCount <= 1) { + ALOGE("%s: ProcessState thread pool max count is %zu. RPC is disabled for this service " + "because RPC requires the service to support multithreading.", + __PRETTY_FUNCTION__, binderThreadPoolMaxCount); + return INVALID_OPERATION; + } + + Extras* e = getOrCreateExtras(); + AutoMutex _l(e->mLock); + if (e->mRpcServer != nullptr) { + ALOGE("%s: Already have RPC client", __PRETTY_FUNCTION__); + return ALREADY_EXISTS; + } + e->mRpcServer = RpcServer::make(); + LOG_ALWAYS_FATAL_IF(e->mRpcServer == nullptr, "RpcServer::make returns null"); + e->mRpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction(); + // Weak ref to avoid circular dependency: BBinder -> RpcServer -X-> BBinder + e->mRpcServer->setRootObjectWeak(wp<BBinder>::fromExisting(this)); + e->mRpcServer->setupExternalServer(std::move(socketFd)); + e->mRpcServer->start(); + LOG_RPC_DETAIL("%s(%d, %" PRIu32 ") successful", __PRETTY_FUNCTION__, socketFdForPrint, + maxRpcThreads); + return OK; +} + BBinder::~BBinder() { Extras* e = mExtras.load(std::memory_order_relaxed); diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index f7ca1e68cb..3095607594 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -359,6 +359,14 @@ status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) { return result; } +size_t ProcessState::getThreadPoolMaxThreadCount() const { + // may actually be one more than this, if join is called + if (mThreadPoolStarted) return mMaxThreads; + // must not be initialized or maybe has poll thread setup, we + // currently don't track this in libbinder + return 0; +} + status_t ProcessState::enableOnewaySpamDetection(bool enable) { uint32_t enableDetection = enable ? 1 : 0; if (ioctl(mDriverFD, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enableDetection) == -1) { diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index 7e9be417e1..754f87cd7e 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -94,6 +94,9 @@ public: pid_t getDebugPid(); + [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd clientFd, + uint32_t maxRpcThreads); + protected: virtual ~BBinder(); @@ -111,6 +114,8 @@ private: Extras* getOrCreateExtras(); + [[nodiscard]] status_t setRpcClientDebug(const Parcel& data); + std::atomic<Extras*> mExtras; friend ::android::internal::Stability; diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h index 97c826ce76..ce28d7c706 100644 --- a/libs/binder/include/binder/IBinder.h +++ b/libs/binder/include/binder/IBinder.h @@ -60,6 +60,7 @@ public: SYSPROPS_TRANSACTION = B_PACK_CHARS('_', 'S', 'P', 'R'), EXTENSION_TRANSACTION = B_PACK_CHARS('_', 'E', 'X', 'T'), DEBUG_PID_TRANSACTION = B_PACK_CHARS('_', 'P', 'I', 'D'), + SET_RPC_CLIENT_TRANSACTION = B_PACK_CHARS('_', 'R', 'P', 'C'), // See android.os.IBinder.TWEET_TRANSACTION // Most importantly, messages can be anything not exceeding 130 UTF-8 @@ -152,6 +153,27 @@ public: */ status_t getDebugPid(pid_t* outPid); + /** + * Set the RPC client fd to this binder service, for debugging. This is only available on + * debuggable builds. + * + * |maxRpcThreads| must be positive because RPC is useless without threads. + * + * When this is called on a binder service, the service: + * 1. sets up RPC server + * 2. spawns 1 new thread that calls RpcServer::join() + * - join() spawns at most |maxRpcThreads| threads that accept() connections; see RpcServer + * + * setRpcClientDebug() may only be called once. + * TODO(b/182914638): If allow to shut down the client, addRpcClient can be called repeatedly. + * + * Note: A thread is spawned for each accept()'ed fd, which may call into functions of the + * interface freely. See RpcServer::join(). To avoid such race conditions, implement the service + * functions with multithreading support. + */ + [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd socketFd, + uint32_t maxRpcThreads); + // NOLINTNEXTLINE(google-default-arguments) virtual status_t transact( uint32_t code, const Parcel& data, diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index b992c04830..72c2ab7b31 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -84,6 +84,13 @@ public: // before any threads are spawned. void setCallRestriction(CallRestriction restriction); + /** + * Get the max number of threads that the kernel can start. + * + * Note: this is the lower bound. Additional threads may be started. + */ + size_t getThreadPoolMaxThreadCount() const; + private: static sp<ProcessState> init(const char* defaultDriver, bool requireDefault); diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index ccd5bf9128..9cf433d6fd 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -60,6 +60,7 @@ cc_test { defaults: ["binder_test_defaults"], srcs: ["binderLibTest.cpp"], shared_libs: [ + "libbase", "libbinder", "libutils", ], @@ -101,6 +102,7 @@ cc_test { srcs: ["binderLibTest.cpp"], shared_libs: [ + "libbase", "libbinder", "libutils", ], diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 963d7b3271..6006fd3c6f 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -21,20 +21,29 @@ #include <pthread.h> #include <stdio.h> #include <stdlib.h> + +#include <chrono> #include <thread> #include <gmock/gmock.h> #include <gtest/gtest.h> +#include <android-base/properties.h> +#include <android-base/result.h> +#include <android-base/unique_fd.h> #include <binder/Binder.h> #include <binder/IBinder.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/ParcelRef.h> +#include <binder/RpcServer.h> +#include <binder/RpcSession.h> #include <linux/sched.h> #include <sys/epoll.h> #include <sys/prctl.h> +#include <sys/socket.h> +#include <sys/un.h> #include "../binder_module.h" #include "binderAbiHelper.h" @@ -42,7 +51,11 @@ #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) using namespace android; +using namespace std::string_literals; +using namespace std::chrono_literals; +using testing::ExplainMatchResult; using testing::Not; +using testing::WithParamInterface; // e.g. EXPECT_THAT(expr, StatusEq(OK)) << "additional message"; MATCHER_P(StatusEq, expected, (negation ? "not " : "") + statusToString(expected)) { @@ -50,6 +63,15 @@ MATCHER_P(StatusEq, expected, (negation ? "not " : "") + statusToString(expected return expected == arg; } +// e.g. Result<int32_t> v = 0; EXPECT_THAT(result, ResultHasValue(0)); +MATCHER_P(ResultHasValue, resultMatcher, "") { + if (!arg.ok()) { + *result_listener << "contains error " << arg.error(); + return false; + } + return ExplainMatchResult(resultMatcher, arg.value(), result_listener); +} + static ::testing::AssertionResult IsPageAligned(void *buf) { if (((unsigned long)buf & ((unsigned long)PAGE_SIZE - 1)) == 0) return ::testing::AssertionSuccess(); @@ -98,6 +120,8 @@ enum BinderLibTestTranscationCode { BINDER_LIB_TEST_ECHO_VECTOR, BINDER_LIB_TEST_REJECT_BUF, BINDER_LIB_TEST_CAN_GET_SID, + BINDER_LIB_TEST_USLEEP, + BINDER_LIB_TEST_CREATE_TEST_SERVICE, }; pid_t start_server_process(int arg2, bool usePoll = false) @@ -158,6 +182,20 @@ pid_t start_server_process(int arg2, bool usePoll = false) return pid; } +android::base::Result<int32_t> GetId(sp<IBinder> service) { + using android::base::Error; + Parcel data, reply; + data.markForBinder(service); + const char *prefix = data.isForRpc() ? "On RPC server, " : "On binder server, "; + status_t status = service->transact(BINDER_LIB_TEST_GET_ID_TRANSACTION, data, &reply); + if (status != OK) + return Error(status) << prefix << "transact(GET_ID): " << statusToString(status); + int32_t result = 0; + status = reply.readInt32(&result); + if (status != OK) return Error(status) << prefix << "readInt32: " << statusToString(status); + return result; +} + class BinderLibTestEnv : public ::testing::Environment { public: BinderLibTestEnv() {} @@ -477,12 +515,7 @@ TEST_F(BinderLibTest, SetError) { } TEST_F(BinderLibTest, GetId) { - int32_t id; - Parcel data, reply; - EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GET_ID_TRANSACTION, data, &reply), - StatusEq(NO_ERROR)); - EXPECT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR)); - EXPECT_EQ(0, id); + EXPECT_THAT(GetId(m_server), ResultHasValue(0)); } TEST_F(BinderLibTest, PtrSize) { @@ -1173,14 +1206,170 @@ TEST_F(BinderLibTest, GotSid) { EXPECT_THAT(server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr), StatusEq(OK)); } +class BinderLibRpcTestBase : public BinderLibTest { +public: + void SetUp() override { + if (!base::GetBoolProperty("ro.debuggable", false)) { + GTEST_SKIP() << "Binder RPC is only enabled on debuggable builds, skipping test on " + "non-debuggable builds."; + } + BinderLibTest::SetUp(); + } + + std::tuple<android::base::unique_fd, unsigned int> CreateSocket() { + auto rpcServer = RpcServer::make(); + EXPECT_NE(nullptr, rpcServer); + if (rpcServer == nullptr) return {}; + rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction(); + unsigned int port; + if (!rpcServer->setupInetServer(0, &port)) { + ADD_FAILURE() << "setupInetServer failed"; + return {}; + } + return {rpcServer->releaseServer(), port}; + } +}; + +class BinderLibRpcTest : public BinderLibRpcTestBase, public WithParamInterface<bool> { +public: + sp<IBinder> GetService() { + return GetParam() ? sp<IBinder>(addServer()) : sp<IBinder>(sp<BBinder>::make()); + } + static std::string ParamToString(const testing::TestParamInfo<ParamType> &info) { + return info.param ? "remote" : "local"; + } +}; + +TEST_P(BinderLibRpcTest, SetRpcMaxThreads) { + auto binder = GetService(); + ASSERT_TRUE(binder != nullptr); + auto [socket, port] = CreateSocket(); + ASSERT_TRUE(socket.ok()); + EXPECT_THAT(binder->setRpcClientDebug(std::move(socket), 1), StatusEq(OK)); +} + +TEST_P(BinderLibRpcTest, SetRpcClientNoFd) { + auto binder = GetService(); + ASSERT_TRUE(binder != nullptr); + EXPECT_THAT(binder->setRpcClientDebug(android::base::unique_fd(), 1), StatusEq(BAD_VALUE)); +} + +TEST_P(BinderLibRpcTest, SetRpcMaxThreadsZero) { + auto binder = GetService(); + ASSERT_TRUE(binder != nullptr); + auto [socket, port] = CreateSocket(); + ASSERT_TRUE(socket.ok()); + EXPECT_THAT(binder->setRpcClientDebug(std::move(socket), 0), StatusEq(BAD_VALUE)); +} + +TEST_P(BinderLibRpcTest, SetRpcMaxThreadsTwice) { + auto binder = GetService(); + ASSERT_TRUE(binder != nullptr); + + auto [socket1, port1] = CreateSocket(); + ASSERT_TRUE(socket1.ok()); + EXPECT_THAT(binder->setRpcClientDebug(std::move(socket1), 1), StatusEq(OK)); + + auto [socket2, port2] = CreateSocket(); + ASSERT_TRUE(socket2.ok()); + EXPECT_THAT(binder->setRpcClientDebug(std::move(socket2), 1), StatusEq(ALREADY_EXISTS)); +} + +INSTANTIATE_TEST_CASE_P(BinderLibTest, BinderLibRpcTest, testing::Bool(), + BinderLibRpcTest::ParamToString); + +class BinderLibTestService; +class BinderLibRpcClientTest : public BinderLibRpcTestBase, + public WithParamInterface<std::tuple<bool, uint32_t>> { +public: + static std::string ParamToString(const testing::TestParamInfo<ParamType> &info) { + auto [isRemote, numThreads] = info.param; + return (isRemote ? "remote" : "local") + "_server_with_"s + std::to_string(numThreads) + + "_threads"; + } + sp<IBinder> CreateRemoteService(int32_t id) { + Parcel data, reply; + status_t status = data.writeInt32(id); + EXPECT_THAT(status, StatusEq(OK)); + if (status != OK) return nullptr; + status = m_server->transact(BINDER_LIB_TEST_CREATE_TEST_SERVICE, data, &reply); + EXPECT_THAT(status, StatusEq(OK)); + if (status != OK) return nullptr; + sp<IBinder> ret; + status = reply.readStrongBinder(&ret); + EXPECT_THAT(status, StatusEq(OK)); + if (status != OK) return nullptr; + return ret; + } +}; + +TEST_P(BinderLibRpcClientTest, Test) { + auto [isRemote, numThreadsParam] = GetParam(); + uint32_t numThreads = numThreadsParam; // ... to be captured in lambda + int32_t id = 0xC0FFEE00 + numThreads; + sp<IBinder> server = isRemote ? sp<IBinder>(CreateRemoteService(id)) + : sp<IBinder>(sp<BinderLibTestService>::make(id, false)); + ASSERT_EQ(isRemote, !!server->remoteBinder()); + ASSERT_THAT(GetId(server), ResultHasValue(id)); + + unsigned int port = 0; + // Fake servicedispatcher. + { + auto [socket, socketPort] = CreateSocket(); + ASSERT_TRUE(socket.ok()); + port = socketPort; + ASSERT_THAT(server->setRpcClientDebug(std::move(socket), numThreads), StatusEq(OK)); + } + + auto callUsleep = [](sp<IBinder> server, uint64_t us) { + Parcel data, reply; + data.markForBinder(server); + const char *name = data.isForRpc() ? "RPC" : "binder"; + EXPECT_THAT(data.writeUint64(us), StatusEq(OK)); + EXPECT_THAT(server->transact(BINDER_LIB_TEST_USLEEP, data, &reply), StatusEq(OK)) + << "for " << name << " server"; + }; + + auto threadFn = [&](size_t threadNum) { + usleep(threadNum * 50 * 1000); // threadNum * 50ms. Need this to avoid SYN flooding. + auto rpcSession = RpcSession::make(); + ASSERT_TRUE(rpcSession->setupInetClient("127.0.0.1", port)); + auto rpcServerBinder = rpcSession->getRootObject(); + ASSERT_NE(nullptr, rpcServerBinder); + + EXPECT_EQ(OK, rpcServerBinder->pingBinder()); + + // Check that |rpcServerBinder| and |server| points to the same service. + EXPECT_THAT(GetId(rpcServerBinder), ResultHasValue(id)); + + // Occupy the server thread. The server should still have enough threads to handle + // other connections. + // (numThreads - threadNum) * 100ms + callUsleep(rpcServerBinder, (numThreads - threadNum) * 100 * 1000); + }; + std::vector<std::thread> threads; + for (size_t i = 0; i < numThreads; ++i) threads.emplace_back(std::bind(threadFn, i)); + for (auto &t : threads) t.join(); +} + +INSTANTIATE_TEST_CASE_P(BinderLibTest, BinderLibRpcClientTest, + testing::Combine(testing::Bool(), testing::Range(1u, 10u)), + BinderLibRpcClientTest::ParamToString); + class BinderLibTestService : public BBinder { public: - explicit BinderLibTestService(int32_t id) - : m_id(id), m_nextServerId(id + 1), m_serverStartRequested(false), m_callback(nullptr) { + explicit BinderLibTestService(int32_t id, bool exitOnDestroy = true) + : m_id(id), + m_nextServerId(id + 1), + m_serverStartRequested(false), + m_callback(nullptr), + m_exitOnDestroy(exitOnDestroy) { pthread_mutex_init(&m_serverWaitMutex, nullptr); pthread_cond_init(&m_serverWaitCond, nullptr); } - ~BinderLibTestService() { exit(EXIT_SUCCESS); } + ~BinderLibTestService() { + if (m_exitOnDestroy) exit(EXIT_SUCCESS); + } void processPendingCall() { if (m_callback != nullptr) { @@ -1193,7 +1382,8 @@ public: virtual status_t onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags = 0) { - if (getuid() != (uid_t)IPCThreadState::self()->getCallingUid()) { + // TODO(b/182914638): also checks getCallingUid() for RPC + if (!data.isForRpc() && getuid() != (uid_t)IPCThreadState::self()->getCallingUid()) { return PERMISSION_DENIED; } switch (code) { @@ -1480,6 +1670,18 @@ public: case BINDER_LIB_TEST_CAN_GET_SID: { return IPCThreadState::self()->getCallingSid() == nullptr ? BAD_VALUE : NO_ERROR; } + case BINDER_LIB_TEST_USLEEP: { + uint64_t us; + if (status_t status = data.readUint64(&us); status != NO_ERROR) return status; + usleep(us); + return NO_ERROR; + } + case BINDER_LIB_TEST_CREATE_TEST_SERVICE: { + int32_t id; + if (status_t status = data.readInt32(&id); status != NO_ERROR) return status; + reply->writeStrongBinder(sp<BinderLibTestService>::make(id, false)); + return NO_ERROR; + } default: return UNKNOWN_TRANSACTION; }; @@ -1494,6 +1696,7 @@ private: sp<IBinder> m_serverStarted; sp<IBinder> m_strongRef; sp<IBinder> m_callback; + bool m_exitOnDestroy; }; int run_server(int index, int readypipefd, bool usePoll) diff --git a/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h index 69f1b9dfb2..72c5bc4342 100644 --- a/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h +++ b/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h @@ -72,6 +72,11 @@ static const std::vector<std::function<void(FuzzedDataProvider*, const sp<BBinde }, [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void { bbinder->getDebugPid(); + }, + [](FuzzedDataProvider* fdp, const sp<BBinder>& bbinder) -> void { + auto rpcMaxThreads = fdp->ConsumeIntegralInRange<uint32_t>(0, 20); + (void)bbinder->setRpcClientDebug(android::base::unique_fd(), + rpcMaxThreads); }}; } // namespace android |