diff options
-rw-r--r-- | libs/binder/RpcState.cpp | 60 | ||||
-rw-r--r-- | libs/binder/RpcState.h | 7 |
2 files changed, 45 insertions, 22 deletions
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 08bf4ec068..93f15294df 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -134,6 +134,15 @@ size_t RpcState::countBinders() { void RpcState::dump() { std::lock_guard<std::mutex> _l(mNodeMutex); + dumpLocked(); +} + +void RpcState::terminate() { + std::unique_lock<std::mutex> _l(mNodeMutex); + terminate(_l); +} + +void RpcState::dumpLocked() { ALOGE("DUMP OF RpcState %p", this); ALOGE("DUMP OF RpcState (%zu nodes)", mNodeForAddress.size()); for (const auto& [address, node] : mNodeForAddress) { @@ -161,10 +170,10 @@ void RpcState::dump() { ALOGE("END DUMP OF RpcState"); } -void RpcState::terminate() { +void RpcState::terminate(std::unique_lock<std::mutex>& lock) { if (SHOULD_LOG_RPC_DETAIL) { ALOGE("RpcState::terminate()"); - dump(); + dumpLocked(); } // if the destructor of a binder object makes another RPC call, then calling @@ -172,20 +181,20 @@ void RpcState::terminate() { // mNodeMutex is no longer taken. std::vector<sp<IBinder>> tempHoldBinder; - { - std::lock_guard<std::mutex> _l(mNodeMutex); - mTerminated = true; - for (auto& [address, node] : mNodeForAddress) { - sp<IBinder> binder = node.binder.promote(); - LOG_ALWAYS_FATAL_IF(binder == nullptr, "Binder %p expected to be owned.", binder.get()); + mTerminated = true; + for (auto& [address, node] : mNodeForAddress) { + sp<IBinder> binder = node.binder.promote(); + LOG_ALWAYS_FATAL_IF(binder == nullptr, "Binder %p expected to be owned.", binder.get()); - if (node.sentRef != nullptr) { - tempHoldBinder.push_back(node.sentRef); - } + if (node.sentRef != nullptr) { + tempHoldBinder.push_back(node.sentRef); } - - mNodeForAddress.clear(); } + + mNodeForAddress.clear(); + + lock.unlock(); + tempHoldBinder.clear(); // explicit } RpcState::CommandData::CommandData(size_t size) : mSize(size) { @@ -341,14 +350,15 @@ status_t RpcState::transactAddress(const base::unique_fd& fd, const RpcAddress& uint64_t asyncNumber = 0; if (!address.isZero()) { - std::lock_guard<std::mutex> _l(mNodeMutex); + std::unique_lock<std::mutex> _l(mNodeMutex); if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races auto it = mNodeForAddress.find(address); LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Sending transact on unknown address %s", address.toString().c_str()); if (flags & IBinder::FLAG_ONEWAY) { - asyncNumber = it->second.asyncNumber++; + asyncNumber = it->second.asyncNumber; + if (!nodeProgressAsyncNumber(&it->second, _l)) return DEAD_OBJECT; } } @@ -697,13 +707,7 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<R // last refcount dropped after this transaction happened if (it == mNodeForAddress.end()) return OK; - // note - only updated now, instead of later, so that other threads - // will queue any later transactions - - // TODO(b/183140903): support > 2**64 async transactions - // (we can do this by allowing asyncNumber to wrap, since we - // don't expect more than 2**64 simultaneous transactions) - it->second.asyncNumber++; + if (!nodeProgressAsyncNumber(&it->second, _l)) return DEAD_OBJECT; if (it->second.asyncTodo.size() == 0) return OK; if (it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) { @@ -822,4 +826,16 @@ sp<IBinder> RpcState::tryEraseNode(std::map<RpcAddress, BinderNode>::iterator& i return ref; } +bool RpcState::nodeProgressAsyncNumber(BinderNode* node, std::unique_lock<std::mutex>& lock) { + // 2**64 =~ 10**19 =~ 1000 transactions per second for 585 million years to + // a single binder + if (node->asyncNumber >= std::numeric_limits<decltype(node->asyncNumber)>::max()) { + ALOGE("Out of async transaction IDs. Terminating"); + terminate(lock); + return false; + } + node->asyncNumber++; + return true; +} + } // namespace android diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h index 2654dff460..81ff458ba7 100644 --- a/libs/binder/RpcState.h +++ b/libs/binder/RpcState.h @@ -113,6 +113,9 @@ public: void terminate(); private: + void dumpLocked(); + void terminate(std::unique_lock<std::mutex>& lock); + // Alternative to std::vector<uint8_t> that doesn't abort on allocation failure and caps // large allocations to avoid being requested from allocating too much data. struct CommandData { @@ -200,6 +203,10 @@ private: // binderNode, this returns that strong reference, so that it can be // dropped after any locks are removed. sp<IBinder> tryEraseNode(std::map<RpcAddress, BinderNode>::iterator& it); + // true - success + // false - state terminated, lock gone, halt + [[nodiscard]] bool nodeProgressAsyncNumber(BinderNode* node, + std::unique_lock<std::mutex>& lock); std::mutex mNodeMutex; bool mTerminated = false; |