From ada72bd2674ed8e04f6d8aa06803b058bad88560 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 9 Jun 2021 23:29:13 +0000 Subject: libbinder: RPC process oneway w/ 'tail call' When draining oneway commands (which must be serialized), we do a recursive call to process a transaction. However, this wouldn't even be considered to be a tailcall because of the complex destructors which need to run. So, instead we work around this w/ goto to the beginning of the function. The alternative here (to a 'goto') to consider is creating a more complex return type to processTransactInternal which would convince processTransact to re-issue the command. Though, this would be a somewhat larger refactor. Fixes: 190638569 Test: binderRpcTest (OnewayStressTest repeatedly on device doesn't fail for several minutes - failed without this) Change-Id: I9fbc75941452348e498849d5d59130487ef6cc44 --- libs/binder/RpcState.cpp | 19 ++++++++++++------- libs/binder/RpcState.h | 3 +-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 6899981e83..62eb58adba 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -565,7 +565,7 @@ status_t RpcState::processTransact(const base::unique_fd& fd, const sp& session, - CommandData transactionData, sp&& targetRef) { + CommandData transactionData) { + // for 'recursive' calls to this, we have already read and processed the + // binder from the transaction data and taken reference counts into account, + // so it is cached here. + sp targetRef; +processTransactInternalTailCall: + if (transactionData.size() < sizeof(RpcWireTransaction)) { ALOGE("Expecting %zu but got %zu bytes for RpcWireTransaction. Terminating!", sizeof(RpcWireTransaction), transactionData.size()); @@ -751,13 +757,12 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp(it->second.asyncTodo.top()); - CommandData nextData = std::move(todo.data); - sp nextRef = std::move(todo.ref); + // reset up arguments + transactionData = std::move(todo.data); + targetRef = std::move(todo.ref); it->second.asyncTodo.pop(); - _l.unlock(); - return processTransactInternal(fd, session, std::move(nextData), - std::move(nextRef)); + goto processTransactInternalTailCall; } } return OK; diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h index 13c31154eb..db142a11f8 100644 --- a/libs/binder/RpcState.h +++ b/libs/binder/RpcState.h @@ -144,8 +144,7 @@ private: const RpcWireHeader& command); [[nodiscard]] status_t processTransactInternal(const base::unique_fd& fd, const sp& session, - CommandData transactionData, - sp&& targetRef); + CommandData transactionData); [[nodiscard]] status_t processDecStrong(const base::unique_fd& fd, const sp& session, const RpcWireHeader& command); -- cgit v1.2.3-59-g8ed1b