diff options
author | 2021-05-10 23:15:08 +0000 | |
---|---|---|
committer | 2021-05-10 23:15:08 +0000 | |
commit | 4fccd098967a1cad0a188672b801bf4e7b515079 (patch) | |
tree | 36f7d713d1630b5a7e4cb1df3d7b231c039d599c | |
parent | c9fb9f924521162fd1959a99d748b6cb35acbb04 (diff) | |
parent | b6a1e7eb34980400bdbabcab756c5a244b1f525b (diff) |
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
-rw-r--r-- | libs/binder/RpcServer.cpp | 12 | ||||
-rw-r--r-- | libs/binder/RpcSession.cpp | 26 | ||||
-rw-r--r-- | libs/binder/RpcState.cpp | 37 | ||||
-rw-r--r-- | libs/binder/RpcState.h | 19 | ||||
-rw-r--r-- | libs/binder/include/binder/RpcServer.h | 4 | ||||
-rw-r--r-- | libs/binder/include/binder/RpcSession.h | 2 |
6 files changed, 85 insertions, 15 deletions
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 786e2db3b3..aaebb23f6f 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -216,4 +216,16 @@ bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) { 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 09ec20dbf0..f4a3cffa24 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 @@ void RpcSession::startThread(unique_fd client) { 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 @@ void RpcSession::join(unique_fd client) { "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 @@ bool RpcSession::removeServerConnection(const sp<RpcConnection>& connection) { 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 96190dc03c..20fdbfe954 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -326,7 +326,11 @@ status_t RpcState::transact(const base::unique_fd& fd, const RpcAddress& address .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 @@ status_t RpcState::waitForReply(const base::unique_fd& fd, const sp<RpcSession>& 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 @@ status_t RpcState::waitForReply(const base::unique_fd& fd, const sp<RpcSession>& 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 @@ status_t RpcState::processTransact(const base::unique_fd& fd, const sp<RpcSessio 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 @@ static void do_nothing_to_transact_data(Parcel* p, const uint8_t* data, size_t d } 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 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<R 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 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<R // 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_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<R .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::processTransactInternal(const base::unique_fd& fd, const sp<R 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 @@ status_t RpcState::processDecStrong(const base::unique_fd& fd, const RpcWireHead 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 3f3eb1c2ed..83d034497f 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 @@ private: */ 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 @@ private: 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 @@ private: // 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 c98151d293..8c9ba00f06 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -109,6 +109,10 @@ public: ~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 3f58b2ce8e..d49d48d40e 100644 --- a/libs/binder/include/binder/RpcSession.h +++ b/libs/binder/include/binder/RpcSession.h @@ -118,6 +118,7 @@ private: 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 @@ private: // 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 |