summaryrefslogtreecommitdiff
path: root/libs/binder/RpcState.cpp
diff options
context:
space:
mode:
author Steven Moreland <smoreland@google.com> 2021-09-28 20:16:31 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2021-09-28 20:16:31 +0000
commita7e51752c22427dc918281ea739f391aab35bf9f (patch)
tree98759a23bdc0a741cd2df8c63320bf4e6e5d5e8d /libs/binder/RpcState.cpp
parent13ba6f3c3fef163b74f33092cdd3ed63c25e2bb3 (diff)
parentd8083310534b157c7e303083df15fe9b362e4913 (diff)
Merge changes Ieb537412,I2339a8e0
* changes: libbinder: oneway calls delay refcounting libbinder: dec refs include count
Diffstat (limited to 'libs/binder/RpcState.cpp')
-rw-r--r--libs/binder/RpcState.cpp103
1 files changed, 77 insertions, 26 deletions
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 1e86104392..3ff13bcd9b 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -152,7 +152,7 @@ status_t RpcState::onBinderEntering(const sp<RpcSession>& session, uint64_t addr
return BAD_VALUE;
}
- std::unique_lock<std::mutex> _l(mNodeMutex);
+ std::lock_guard<std::mutex> _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT;
if (auto it = mNodeForAddress.find(address); it != mNodeForAddress.end()) {
@@ -160,13 +160,7 @@ status_t RpcState::onBinderEntering(const sp<RpcSession>& session, uint64_t addr
// implicitly have strong RPC refcount, since we received this binder
it->second.timesRecd++;
-
- _l.unlock();
-
- // We have timesRecd RPC refcounts, but we only need to hold on to one
- // when we keep the object. All additional dec strongs are sent
- // immediately, we wait to send the last one in BpBinder::onLastDecStrong.
- return session->sendDecStrong(address);
+ return OK;
}
// we don't know about this binder, so the other side of the connection
@@ -187,6 +181,36 @@ status_t RpcState::onBinderEntering(const sp<RpcSession>& session, uint64_t addr
return OK;
}
+status_t RpcState::flushExcessBinderRefs(const sp<RpcSession>& session, uint64_t address,
+ const sp<IBinder>& binder) {
+ std::unique_lock<std::mutex> _l(mNodeMutex);
+ if (mTerminated) return DEAD_OBJECT;
+
+ auto it = mNodeForAddress.find(address);
+
+ LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Can't be deleted while we hold sp<>");
+ LOG_ALWAYS_FATAL_IF(it->second.binder != binder,
+ "Caller of flushExcessBinderRefs using inconsistent arguments");
+
+ // if this is a local binder, then we want to get rid of all refcounts
+ // (tell the other process it can drop the binder when it wants to - we
+ // have a local sp<>, so we will drop it when we want to as well). if
+ // this is a remote binder, then we need to hold onto one refcount until
+ // it is dropped in BpBinder::onLastStrongRef
+ size_t targetRecd = binder->localBinder() ? 0 : 1;
+
+ // We have timesRecd RPC refcounts, but we only need to hold on to one
+ // when we keep the object. All additional dec strongs are sent
+ // immediately, we wait to send the last one in BpBinder::onLastDecStrong.
+ if (it->second.timesRecd != targetRecd) {
+ _l.unlock();
+
+ return session->sendDecStrongToTarget(address, targetRecd);
+ }
+
+ return OK;
+}
+
size_t RpcState::countBinders() {
std::lock_guard<std::mutex> _l(mNodeMutex);
return mNodeForAddress.size();
@@ -571,32 +595,43 @@ status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
return OK;
}
-status_t RpcState::sendDecStrong(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, uint64_t addr) {
+status_t RpcState::sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, uint64_t addr,
+ size_t target) {
+ RpcDecStrong body = {
+ .address = RpcWireAddress::fromRaw(addr),
+ };
+
{
std::lock_guard<std::mutex> _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
auto it = mNodeForAddress.find(addr);
LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
"Sending dec strong on unknown address %" PRIu64, addr);
- LOG_ALWAYS_FATAL_IF(it->second.timesRecd <= 0, "Bad dec strong %" PRIu64, addr);
- it->second.timesRecd--;
+ LOG_ALWAYS_FATAL_IF(it->second.timesRecd < target, "Can't dec count of %zu to %zu.",
+ it->second.timesRecd, target);
+
+ // typically this happens when multiple threads send dec refs at the
+ // same time - the transactions will get combined automatically
+ if (it->second.timesRecd == target) return OK;
+
+ body.amount = it->second.timesRecd - target;
+ it->second.timesRecd = target;
+
LOG_ALWAYS_FATAL_IF(nullptr != tryEraseNode(it),
"Bad state. RpcState shouldn't own received binder");
}
RpcWireHeader cmd = {
.command = RPC_COMMAND_DEC_STRONG,
- .bodySize = sizeof(RpcWireAddress),
+ .bodySize = sizeof(RpcDecStrong),
};
if (status_t status = rpcSend(connection, session, "dec ref header", &cmd, sizeof(cmd));
status != OK)
return status;
- if (status_t status = rpcSend(connection, session, "dec ref body", &addr, sizeof(addr));
- status != OK)
- return status;
- return OK;
+
+ return rpcSend(connection, session, "dec ref body", &body, sizeof(body));
}
status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection,
@@ -827,6 +862,12 @@ processTransactInternalTailCall:
}
}
+ // Binder refs are flushed for oneway calls only after all calls which are
+ // built up are executed. Otherwise, they fill up the binder buffer.
+ if (addr != 0 && replyStatus == OK && !oneway) {
+ replyStatus = flushExcessBinderRefs(session, addr, target);
+ }
+
if (oneway) {
if (replyStatus != OK) {
ALOGW("Oneway call failed with error: %d", replyStatus);
@@ -875,6 +916,13 @@ processTransactInternalTailCall:
goto processTransactInternalTailCall;
}
}
+
+ // done processing all the async commands on this binder that we can, so
+ // write decstrongs on the binder
+ if (addr != 0 && replyStatus == OK) {
+ return flushExcessBinderRefs(session, addr, target);
+ }
+
return OK;
}
@@ -916,16 +964,15 @@ status_t RpcState::processDecStrong(const sp<RpcSession::RpcConnection>& connect
status != OK)
return status;
- if (command.bodySize != sizeof(RpcWireAddress)) {
- ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireAddress. Terminating!",
- sizeof(RpcWireAddress), command.bodySize);
+ if (command.bodySize != sizeof(RpcDecStrong)) {
+ ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcDecStrong. Terminating!",
+ sizeof(RpcDecStrong), command.bodySize);
(void)session->shutdownAndWait(false);
return BAD_VALUE;
}
- RpcWireAddress* address = reinterpret_cast<RpcWireAddress*>(commandData.data());
-
- uint64_t addr = RpcWireAddress::toRaw(*address);
+ RpcDecStrong* body = reinterpret_cast<RpcDecStrong*>(commandData.data());
+ uint64_t addr = RpcWireAddress::toRaw(body->address);
std::unique_lock<std::mutex> _l(mNodeMutex);
auto it = mNodeForAddress.find(addr);
if (it == mNodeForAddress.end()) {
@@ -943,15 +990,19 @@ status_t RpcState::processDecStrong(const sp<RpcSession::RpcConnection>& connect
return BAD_VALUE;
}
- if (it->second.timesSent == 0) {
- ALOGE("No record of sending binder, but requested decStrong: %" PRIu64, addr);
+ if (it->second.timesSent < body->amount) {
+ ALOGE("Record of sending binder %zu times, but requested decStrong for %" PRIu64 " of %u",
+ it->second.timesSent, addr, body->amount);
return OK;
}
LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %" PRIu64,
addr);
- it->second.timesSent--;
+ LOG_RPC_DETAIL("Processing dec strong of %" PRIu64 " by %u from %zu", addr, body->amount,
+ it->second.timesSent);
+
+ it->second.timesSent -= body->amount;
sp<IBinder> tempHold = tryEraseNode(it);
_l.unlock();
tempHold = nullptr; // destructor may make binder calls on this session