summaryrefslogtreecommitdiff
path: root/libs/binder/RpcState.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/binder/RpcState.cpp')
-rw-r--r--libs/binder/RpcState.cpp60
1 files changed, 38 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