Merge changes Ic0719395,Id9f1b639,I00474797,Ide06476a
* changes:
libbinder: remove RpcState deadlock debug logs
libbinder: RPC avoid abort on too big allocations
libbinder: RPC avoid server shutdown crash
libbinder: delete dead server objects
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 786e2db..aaebb23 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -216,4 +216,16 @@
return true;
}
+void RpcServer::onSessionTerminating(const sp<RpcSession>& session) {
+ auto id = session->mId;
+ LOG_ALWAYS_FATAL_IF(id == std::nullopt, "Server sessions must be initialized with ID");
+ LOG_RPC_DETAIL("Dropping session %d", *id);
+
+ std::lock_guard<std::mutex> _l(mLock);
+ auto it = mSessions.find(*id);
+ LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %d", *id);
+ LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %d", *id);
+ (void)mSessions.erase(it);
+}
+
} // namespace android
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 09ec20d..f4a3cff 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -24,6 +24,7 @@
#include <string_view>
#include <binder/Parcel.h>
+#include <binder/RpcServer.h>
#include <binder/Stability.h>
#include <utils/String8.h>
@@ -142,8 +143,10 @@
holdThis->join(unique_fd(fd));
{
std::lock_guard<std::mutex> _l(holdThis->mMutex);
- size_t erased = mThreads.erase(std::this_thread::get_id());
- LOG_ALWAYS_FATAL_IF(erased != 0, "Could not erase thread.");
+ auto it = mThreads.find(std::this_thread::get_id());
+ LOG_ALWAYS_FATAL_IF(it == mThreads.end());
+ it->second.detach();
+ mThreads.erase(it);
}
});
mThreads[thread.get_id()] = std::move(thread);
@@ -168,6 +171,22 @@
"bad state: connection object guaranteed to be in list");
}
+void RpcSession::terminateLocked() {
+ // TODO(b/185167543):
+ // - kindly notify other side of the connection of termination (can't be
+ // locked)
+ // - prevent new client/servers from being added
+ // - stop all threads which are currently reading/writing
+ // - terminate RpcState?
+
+ if (mTerminated) return;
+
+ sp<RpcServer> server = mForServer.promote();
+ if (server) {
+ server->onSessionTerminating(sp<RpcSession>::fromExisting(this));
+ }
+}
+
wp<RpcServer> RpcSession::server() {
return mForServer;
}
@@ -264,6 +283,9 @@
std::lock_guard<std::mutex> _l(mMutex);
if (auto it = std::find(mServers.begin(), mServers.end(), connection); it != mServers.end()) {
mServers.erase(it);
+ if (mServers.size() == 0) {
+ terminateLocked();
+ }
return true;
}
return false;
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 96190dc..20fdbfe 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -326,7 +326,11 @@
.asyncNumber = asyncNumber,
};
- std::vector<uint8_t> transactionData(sizeof(RpcWireTransaction) + data.dataSize());
+ ByteVec transactionData(sizeof(RpcWireTransaction) + data.dataSize());
+ if (!transactionData.valid()) {
+ return NO_MEMORY;
+ }
+
memcpy(transactionData.data() + 0, &transaction, sizeof(RpcWireTransaction));
memcpy(transactionData.data() + sizeof(RpcWireTransaction), data.data(), data.dataSize());
@@ -379,9 +383,12 @@
if (status != OK) return status;
}
- uint8_t* data = new uint8_t[command.bodySize];
+ ByteVec data(command.bodySize);
+ if (!data.valid()) {
+ return NO_MEMORY;
+ }
- if (!rpcRec(fd, "reply body", data, command.bodySize)) {
+ if (!rpcRec(fd, "reply body", data.data(), command.bodySize)) {
return DEAD_OBJECT;
}
@@ -391,9 +398,10 @@
terminate();
return BAD_VALUE;
}
- RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data);
+ RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data.data());
if (rpcReply->status != OK) return rpcReply->status;
+ data.release();
reply->ipcSetDataReference(rpcReply->data, command.bodySize - offsetof(RpcWireReply, data),
nullptr, 0, cleanup_reply_data);
@@ -461,7 +469,10 @@
const RpcWireHeader& command) {
LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_TRANSACT, "command: %d", command.command);
- std::vector<uint8_t> transactionData(command.bodySize);
+ ByteVec transactionData(command.bodySize);
+ if (!transactionData.valid()) {
+ return NO_MEMORY;
+ }
if (!rpcRec(fd, "transaction body", transactionData.data(), transactionData.size())) {
return DEAD_OBJECT;
}
@@ -479,7 +490,7 @@
}
status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<RpcSession>& session,
- std::vector<uint8_t>&& transactionData) {
+ ByteVec transactionData) {
if (transactionData.size() < sizeof(RpcWireTransaction)) {
ALOGE("Expecting %zu but got %zu bytes for RpcWireTransaction. Terminating!",
sizeof(RpcWireTransaction), transactionData.size());
@@ -500,7 +511,6 @@
auto it = mNodeForAddress.find(addr);
if (it == mNodeForAddress.end()) {
ALOGE("Unknown binder address %s.", addr.toString().c_str());
- dump();
replyStatus = BAD_VALUE;
} else {
target = it->second.binder.promote();
@@ -630,7 +640,7 @@
// justification for const_cast (consider avoiding priority_queue):
// - AsyncTodo operator< doesn't depend on 'data' object
// - gotta go fast
- std::vector<uint8_t> data = std::move(
+ ByteVec data = std::move(
const_cast<BinderNode::AsyncTodo&>(it->second.asyncTodo.top()).data);
it->second.asyncTodo.pop();
_l.unlock();
@@ -644,7 +654,10 @@
.status = replyStatus,
};
- std::vector<uint8_t> replyData(sizeof(RpcWireReply) + reply.dataSize());
+ ByteVec replyData(sizeof(RpcWireReply) + reply.dataSize());
+ if (!replyData.valid()) {
+ return NO_MEMORY;
+ }
memcpy(replyData.data() + 0, &rpcReply, sizeof(RpcWireReply));
memcpy(replyData.data() + sizeof(RpcWireReply), reply.data(), reply.dataSize());
@@ -671,7 +684,10 @@
status_t RpcState::processDecStrong(const base::unique_fd& fd, const RpcWireHeader& command) {
LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_DEC_STRONG, "command: %d", command.command);
- std::vector<uint8_t> commandData(command.bodySize);
+ ByteVec commandData(command.bodySize);
+ if (!commandData.valid()) {
+ return NO_MEMORY;
+ }
if (!rpcRec(fd, "dec ref body", commandData.data(), commandData.size())) {
return DEAD_OBJECT;
}
@@ -690,7 +706,6 @@
auto it = mNodeForAddress.find(addr);
if (it == mNodeForAddress.end()) {
ALOGE("Unknown binder address %s for dec strong.", addr.toString().c_str());
- dump();
return OK;
}
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 3f3eb1c..83d0344 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -21,6 +21,7 @@
#include <binder/RpcSession.h>
#include <map>
+#include <optional>
#include <queue>
namespace android {
@@ -100,6 +101,20 @@
*/
void terminate();
+ // alternative to std::vector<uint8_t> that doesn't abort on too big of allocations
+ struct ByteVec {
+ explicit ByteVec(size_t size)
+ : mData(size > 0 ? new (std::nothrow) uint8_t[size] : nullptr), mSize(size) {}
+ bool valid() { return mSize == 0 || mData != nullptr; }
+ size_t size() { return mSize; }
+ uint8_t* data() { return mData.get(); }
+ uint8_t* release() { return mData.release(); }
+
+ private:
+ std::unique_ptr<uint8_t[]> mData;
+ size_t mSize;
+ };
+
[[nodiscard]] bool rpcSend(const base::unique_fd& fd, const char* what, const void* data,
size_t size);
[[nodiscard]] bool rpcRec(const base::unique_fd& fd, const char* what, void* data, size_t size);
@@ -113,7 +128,7 @@
const RpcWireHeader& command);
[[nodiscard]] status_t processTransactInternal(const base::unique_fd& fd,
const sp<RpcSession>& session,
- std::vector<uint8_t>&& transactionData);
+ ByteVec transactionData);
[[nodiscard]] status_t processDecStrong(const base::unique_fd& fd,
const RpcWireHeader& command);
@@ -148,7 +163,7 @@
// async transaction queue, _only_ for local binder
struct AsyncTodo {
- std::vector<uint8_t> data; // most convenient format, to move it here
+ ByteVec data;
uint64_t asyncNumber = 0;
bool operator<(const AsyncTodo& o) const {
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index c98151d..8c9ba00 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -109,6 +109,10 @@
~RpcServer();
+ // internal use only
+
+ void onSessionTerminating(const sp<RpcSession>& session);
+
private:
friend sp<RpcServer>;
RpcServer();
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 3f58b2c..d49d48d 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -118,6 +118,7 @@
void startThread(base::unique_fd client);
void join(base::unique_fd client);
+ void terminateLocked();
struct RpcConnection : public RefBase {
base::unique_fd fd;
@@ -196,6 +197,7 @@
// TODO(b/185167543): allow sharing between different sessions in a
// process? (or combine with mServers)
std::map<std::thread::id, std::thread> mThreads;
+ bool mTerminated = false;
};
} // namespace android