Loading libs/binder/Android.bp +4 −0 Original line number Diff line number Diff line Loading @@ -167,6 +167,10 @@ cc_library { binder32bit: { cflags: ["-DBINDER_IPC_32BIT=1"], }, debuggable: { cflags: ["-DBINDER_RPC_DEV_SERVERS"], }, }, shared_libs: [ Loading libs/binder/Binder.cpp +116 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() Loading Loading @@ -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 Loading @@ -150,6 +191,7 @@ public: // for below objects Mutex mLock; sp<RpcServer> mRpcServer; BpBinder::ObjectManager mObjects; }; Loading Loading @@ -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; Loading Loading @@ -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); Loading libs/binder/ProcessState.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading libs/binder/include/binder/Binder.h +5 −0 Original line number Diff line number Diff line Loading @@ -94,6 +94,9 @@ public: pid_t getDebugPid(); [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd clientFd, uint32_t maxRpcThreads); protected: virtual ~BBinder(); Loading @@ -111,6 +114,8 @@ private: Extras* getOrCreateExtras(); [[nodiscard]] status_t setRpcClientDebug(const Parcel& data); std::atomic<Extras*> mExtras; friend ::android::internal::Stability; Loading libs/binder/include/binder/IBinder.h +22 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading Loading
libs/binder/Android.bp +4 −0 Original line number Diff line number Diff line Loading @@ -167,6 +167,10 @@ cc_library { binder32bit: { cflags: ["-DBINDER_IPC_32BIT=1"], }, debuggable: { cflags: ["-DBINDER_RPC_DEV_SERVERS"], }, }, shared_libs: [ Loading
libs/binder/Binder.cpp +116 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() Loading Loading @@ -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 Loading @@ -150,6 +191,7 @@ public: // for below objects Mutex mLock; sp<RpcServer> mRpcServer; BpBinder::ObjectManager mObjects; }; Loading Loading @@ -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; Loading Loading @@ -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); Loading
libs/binder/ProcessState.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading
libs/binder/include/binder/Binder.h +5 −0 Original line number Diff line number Diff line Loading @@ -94,6 +94,9 @@ public: pid_t getDebugPid(); [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd clientFd, uint32_t maxRpcThreads); protected: virtual ~BBinder(); Loading @@ -111,6 +114,8 @@ private: Extras* getOrCreateExtras(); [[nodiscard]] status_t setRpcClientDebug(const Parcel& data); std::atomic<Extras*> mExtras; friend ::android::internal::Stability; Loading
libs/binder/include/binder/IBinder.h +22 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading